[med-svn] [r-cran-rhandsontable] 01/02: New upstream version 0.3.4

Andreas Tille tille at debian.org
Tue Oct 10 21:04:24 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-rhandsontable.

commit 27e677f6d4944777913cf545e51c4c5f5bc6a427
Author: Andreas Tille <tille at debian.org>
Date:   Tue Oct 10 23:01:03 2017 +0200

    New upstream version 0.3.4
---
 DESCRIPTION                                        |   58 +
 LICENSE                                            |    2 +
 LICENSE.note                                       |  222 +++
 MD5                                                |   40 +
 NAMESPACE                                          |   23 +
 NEWS                                               |  125 ++
 R/editAddin.R                                      |  138 ++
 R/misc.R                                           |  138 ++
 R/rhandsontable-package.R                          |   26 +
 R/rhandsontable.R                                  |  750 ++++++++
 build/vignette.rds                                 |  Bin 0 -> 220 bytes
 inst/doc/intro_rhandsontable.R                     |  381 ++++
 inst/doc/intro_rhandsontable.Rmd                   |  620 +++++++
 inst/doc/intro_rhandsontable.html                  |  650 +++++++
 inst/htmlwidgets/lib/chroma/chroma.min.js          |   33 +
 .../lib/handsontable/handsontable.full.min.css     |   31 +
 .../lib/handsontable/handsontable.full.min.js      |   89 +
 inst/htmlwidgets/lib/jquery/jquery.min.js          |    4 +
 inst/htmlwidgets/lib/numbro/languages.js           | 1932 ++++++++++++++++++++
 .../lib/sparkline/jquery.sparkline.min.js          |    4 +
 inst/htmlwidgets/rhandsontable.css                 |   27 +
 inst/htmlwidgets/rhandsontable.js                  |  412 +++++
 inst/htmlwidgets/rhandsontable.yaml                |   27 +
 inst/rstudio/addins.dcf                            |    4 +
 man/editAddin.Rd                                   |   26 +
 man/hot_cell.Rd                                    |   35 +
 man/hot_col.Rd                                     |   81 +
 man/hot_cols.Rd                                    |   45 +
 man/hot_context_menu.Rd                            |   46 +
 man/hot_heatmap.Rd                                 |   35 +
 man/hot_rows.Rd                                    |   33 +
 man/hot_table.Rd                                   |   54 +
 man/hot_to_r.Rd                                    |   19 +
 man/hot_validate_character.Rd                      |   36 +
 man/hot_validate_numeric.Rd                        |   44 +
 man/rHandsontableOutput.Rd                         |   21 +
 man/renderRHandsontable.Rd                         |   23 +
 man/rhandsontable-exports.Rd                       |   12 +
 man/rhandsontable-package.Rd                       |   13 +
 man/rhandsontable.Rd                               |   60 +
 vignettes/intro_rhandsontable.Rmd                  |  620 +++++++
 41 files changed, 6939 insertions(+)

diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..b29d608
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,58 @@
+Package: rhandsontable
+Type: Package
+Title: Interface to the 'Handsontable.js' Library
+Version: 0.3.4
+Authors at R: c(
+  person("Jonathan", "Owen", email = "jonathanro at gmail.com",
+         role = c("aut", "cre", "cph")),
+  person("Jeff", "Allen", role = c("ctb")),
+  person("Yihui", "Xie", role = c("ctb")),
+  person("Enzo", "Martoglio",
+         email = "enzo at smartinsightsfromdata.com", role = c("ctb")),
+  person("Warpechowski", "Marcin", role = c("ctb", "cph"), comment = "Handsontable.js library"),
+  person("Handsoncode sp. z o.o.", role = c("ctb", "cph"), comment = "Handsontable.js library"),
+  person("Aisch", "Gregor", role = c("ctb", "cph"), comment = "Chroma.js library"),
+  person("F<c3><b6>retagsplatsen", role = c("ctb", "cph"), comment = "Numbro.js library"),
+  person("Draper", "Adam", role = c("ctb", "cph"), comment = "Numeral.js library"),
+  person("Wood", "Tim", role = c("ctb", "cph"), comment = "Moment.js library"),
+  person("Chernev", "Iskren", role = c("ctb", "cph"), comment = "Moment.js library"),
+  person("Moment.js contributors", role = c("ctb", "cph"), comment = "Moment.js library"),
+  person("Bushell", "David", role = c("ctb", "cph"), comment = "Pikaday.js library"),
+  person("jQuery Foundation", role = c("ctb", "cph"), comment = "jQuery.js library"),
+  person("Splunk Inc", role = c("ctb", "cph"), comment = "Sparkline.js library"),
+  person("Russell", "Kent", role = c("ctb", "cph"), comment = "Sparkline.js library"),
+  person("Rohan", "Jon", role = c("ctb", "cph"), comment = "ZeroClipboard library"),
+  person("Greene", "James", role = c("ctb", "cph"), comment = "ZeroClipboard library"))
+Maintainer: Jonathan Owen <jonathanro at gmail.com>
+Description: An R interface to the 'Handsontable' JavaScript library, which is a
+    minimalist Excel-like data grid editor.  See <https://handsontable.com/> for details.
+License: MIT + file LICENSE
+URL: http://jrowen.github.io/rhandsontable/
+BugReports: https://github.com/jrowen/rhandsontable/issues
+Imports: jsonlite, htmlwidgets (>= 0.3.3), magrittr, methods
+Suggests: knitr, rmarkdown, shiny (>= 0.13), miniUI (>= 0.1.1),
+        rstudioapi (>= 0.6), htmltools
+VignetteBuilder: knitr
+RoxygenNote: 5.0.1
+NeedsCompilation: no
+Packaged: 2016-11-03 18:59:34 UTC; jonathan
+Author: Jonathan Owen [aut, cre, cph],
+  Jeff Allen [ctb],
+  Yihui Xie [ctb],
+  Enzo Martoglio [ctb],
+  Warpechowski Marcin [ctb, cph] (Handsontable.js library),
+  Handsoncode sp. z o.o. [ctb, cph] (Handsontable.js library),
+  Aisch Gregor [ctb, cph] (Chroma.js library),
+  F<c3><b6>retagsplatsen [ctb, cph] (Numbro.js library),
+  Draper Adam [ctb, cph] (Numeral.js library),
+  Wood Tim [ctb, cph] (Moment.js library),
+  Chernev Iskren [ctb, cph] (Moment.js library),
+  Moment.js contributors [ctb, cph] (Moment.js library),
+  Bushell David [ctb, cph] (Pikaday.js library),
+  jQuery Foundation [ctb, cph] (jQuery.js library),
+  Splunk Inc [ctb, cph] (Sparkline.js library),
+  Russell Kent [ctb, cph] (Sparkline.js library),
+  Rohan Jon [ctb, cph] (ZeroClipboard library),
+  Greene James [ctb, cph] (ZeroClipboard library)
+Repository: CRAN
+Date/Publication: 2016-11-03 21:10:31
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..20bc433
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2015-2016
+COPYRIGHT HOLDER: Marcin Warpechowski, Handsoncode sp. z o.o., Gregor Aisch, Tim Wood, Iskren Chernev, Moment.js contributors, David Bushell, jQuery Foundation, Splunk Inc, Jon Rohan, James M. Greeneand, Företagsplatsen, Kent Russell and Jonathan Owen
diff --git a/LICENSE.note b/LICENSE.note
new file mode 100644
index 0000000..e9f9598
--- /dev/null
+++ b/LICENSE.note
@@ -0,0 +1,222 @@
+The rhandsontable package as a whole is distributed under MIT.
+
+The rhandsontable package includes other open source software components. The following
+is a list of these components (full copies of the license agreements used by
+these components are included below):
+
+- handsontable.js, http://handsontable.com/
+- chroma.js, http://old.driven-by-data.net/about/chromajs/
+- moment.js, http://momentjs.com/
+- pikaday.js, https://github.com/dbushell/Pikaday
+- ZeroClipboard, http://zeroclipboard.org/
+- jquery, https://github.com/jquery/jquery
+- sparkline.js, http://omnipotent.net/jquery.sparkline/
+
+handsontable.js license
+---------------------------------------------------------------------
+(The MIT License)
+
+Copyright (c) 2012-2014 Marcin Warpechowski
+Copyright (c) 2015 Handsoncode sp. z o.o. <hello at handsontable.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+chroma.js license
+---------------------------------------------------------------------
+chroma.js - JavaScript library for color conversions
+
+Copyright (c) 2011-2015, Gregor Aisch
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. The name Gregor Aisch may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+moment.js license
+---------------------------------------------------------------------
+Copyright (c) 2011-2016 Tim Wood, Iskren Chernev, Moment.js contributors
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+pikaday.js license
+---------------------------------------------------------------------
+Copyright (c) 2014 David Bushell BSD & MIT license
+
+The MIT License (MIT)
+
+Copyright (c) 2014 David Bushell
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+The BSD License
+
+Copyright (c) 2014 David Bushell
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ZeroClipboard license
+---------------------------------------------------------------------
+The MIT License (MIT)
+Copyright (c) 2009-2014 Jon Rohan, James M. Greene
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+jQuery license
+----------------------------------------------------------------------
+Copyright jQuery Foundation and other contributors, https://jquery.org/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+sparkline.js license
+----------------------------------------------------------------------
+License: New BSD License
+
+Copyright (c) 2012, Splunk Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+   * Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above copyright notice,
+     this list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+   * Neither the name of Splunk Inc nor the names of its contributors may
+     be used to endorse or promote products derived from this software without
+     specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..e1b9ff6
--- /dev/null
+++ b/MD5
@@ -0,0 +1,40 @@
+b3ae929a5c1662d31677c66bfb318c28 *DESCRIPTION
+40351f714fa68808d751241bf7d37997 *LICENSE
+9ea826f959dfe30a573d04e0dfe9d817 *LICENSE.note
+ff6db4cdb7c4aac5c5ad3b4df6b8fdc0 *NAMESPACE
+8f685c0c7a30ba58640c585530070f34 *NEWS
+00b830baa7a482b1b2dc0204ea13bd6f *R/editAddin.R
+8ffb61204b9823105848550184ffba63 *R/misc.R
+20d0e3db87268efd54b8b8e0f29f0e7d *R/rhandsontable-package.R
+b42400ea10d4f755c6ef9acfa323b5bd *R/rhandsontable.R
+66630722f8ed223fc3777f77fbdc66da *build/vignette.rds
+d9907906132fb2dc991c0d279e284abe *inst/doc/intro_rhandsontable.R
+7679d2c8bd5ed5f373dc9aee3c235844 *inst/doc/intro_rhandsontable.Rmd
+fe992e3aa6cee8c078cd9a831ed68cf8 *inst/doc/intro_rhandsontable.html
+e766d3f5e75c65ca501135eabdca2c9f *inst/htmlwidgets/lib/chroma/chroma.min.js
+8da477b4116e46580c24aa65d57d248e *inst/htmlwidgets/lib/handsontable/handsontable.full.min.css
+9afdab4f619fc60035ae30eedf1c9893 *inst/htmlwidgets/lib/handsontable/handsontable.full.min.js
+6cbb321051a268424103cd4aea8ffa66 *inst/htmlwidgets/lib/jquery/jquery.min.js
+90a7cf84849305282cde9f551e5ae427 *inst/htmlwidgets/lib/numbro/languages.js
+29e61d23be70a7faf60415ee054634f2 *inst/htmlwidgets/lib/sparkline/jquery.sparkline.min.js
+5b795fe97b29521ae8e492fbe57c1b2c *inst/htmlwidgets/rhandsontable.css
+5d4f6756a7f22e330092cf2ba530d032 *inst/htmlwidgets/rhandsontable.js
+f9c8f84a8c9cfe57fe2d5a3e231c304f *inst/htmlwidgets/rhandsontable.yaml
+fec160cd614f037b7768cf55ee2a751f *inst/rstudio/addins.dcf
+b8babc6e09dc4ed9acc9f19efdb37d31 *man/editAddin.Rd
+cac09fb539f6a981eb2ab22cfaa9a7c4 *man/hot_cell.Rd
+844815fd344c79bf88579b69e40aa7da *man/hot_col.Rd
+7f1fbc4718cf8446d555d0da86b24b62 *man/hot_cols.Rd
+bb15e12b2e6ae131af9f3135aad85a26 *man/hot_context_menu.Rd
+01bff48dfeca62b84f368d31b4907257 *man/hot_heatmap.Rd
+1318d086ced86d0d7d7ed56533c5064b *man/hot_rows.Rd
+ca5c5f3fb437ed4e70bc163a884d608d *man/hot_table.Rd
+44d37116641bc8307806aade4f778880 *man/hot_to_r.Rd
+486fcb8fffb8c4a41f123887837c0fba *man/hot_validate_character.Rd
+0e14179c2f9cb2f1566e7fa01d48970d *man/hot_validate_numeric.Rd
+a2536cd4e0633fb3556f79d397e47b9f *man/rHandsontableOutput.Rd
+6917830c6645870845f5af60cf8bb9ae *man/renderRHandsontable.Rd
+c735bb10cdc4e15eaa177974b311f7eb *man/rhandsontable-exports.Rd
+b55aa9eaa7ec956880b92cc2c0510f5b *man/rhandsontable-package.Rd
+ac83e19d6d6ec3f974a57a079ab30b4e *man/rhandsontable.Rd
+7679d2c8bd5ed5f373dc9aee3c235844 *vignettes/intro_rhandsontable.Rmd
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..808bb24
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,23 @@
+# Generated by roxygen2: do not edit by hand
+
+export("%>%")
+export(editAddin)
+export(hot_cell)
+export(hot_col)
+export(hot_cols)
+export(hot_context_menu)
+export(hot_heatmap)
+export(hot_rows)
+export(hot_table)
+export(hot_to_r)
+export(hot_validate_character)
+export(hot_validate_numeric)
+export(rHandsontableOutput)
+export(renderRHandsontable)
+export(rhandsontable)
+import(htmlwidgets)
+import(jsonlite)
+importFrom(magrittr,"%>%")
+importFrom(methods,as)
+importFrom(utils,capture.output)
+importFrom(utils,modifyList)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..c17e47d
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,125 @@
+rhandsontable 0.3.4
+-------------------------
+
+* Added the ability to pass custom parameters to the table.  A good example of their use can be found in the row Custom Renderer Using an R Parameter example (http://jrowen.github.io/rhandsontable/#custom_renderer) and rhandsontable_highlight shiny app.
+
+* Updated to handsontable 0.28.4 (see https://github.com/handsontable/handsontable/releases).
+
+* Fixed an issue with the auto column width (#109)
+
+* Fixed an issues with row.names (#112)
+
+* Fixed an issue with update event order (#111, #113)
+
+* Fixed an issue with the rhandsontable_datafile example (#117)
+
+rhandsontable 0.3.3
+-------------------------
+
+* POSSIBLE BREAKING CHANGE: Updated shiny logic to fire an afterChange event when the table is first populated.  This should not initialize the table input when first loaded and simplify shiny logic.
+
+* Updated to handsontable 0.26.1 (see https://github.com/handsontable/handsontable/releases).  Note the the number formatting library has switched to numbro.js (http://numbrojs.com/languages.html), and the format for the language parameter has changed slightly (e.g. en-US, de-DE, ja-JP, etc.)
+
+* Updated toR parser to support data.table.
+
+* Fixed bug with toR when table column names differ from data column names (#100)
+
+rhandsontable 0.3.2
+-------------------------
+
+* Updates to handsontable 0.25.1 (see https://github.com/handsontable/handsontable/releases).
+
+* Added Edit a Data Frame addin for RStudio
+
+* Added a language parameter to hot_col that supports changing the column formatting locale
+
+* Added rowHeaderWidth to hot_table to allow specifying the rowHeader column width
+
+* Added digits to rhandsontable, which is passed to jsonlite::toJSON
+
+* Fixed shiny bug with mixed numeric and character column names (#77)
+
+rhandsontable 0.3.1
+-------------------------
+
+* Fixed bug with comments (#66)
+
+* Fixed bug with single column table (#69)
+
+* Added overflow parameter to hot_table
+
+* Updates to handsontable 0.23.0 (see https://github.com/handsontable/handsontable/releases).
+
+rhandsontable 0.3
+-------------------------
+
+* Updated to handsontable 0.20.1 (see https://github.com/handsontable/handsontable/releases).  Row and column grouping no longer supported in open source version.
+
+* Fixed a bug that didn't return the changed column and row index when the table is sorted (#56)
+
+* Fixed a bug that didn't allow column formatting when the column headers were NULL (#57)
+
+rhandsontable 0.2.2
+-------------------------
+
+* Added support in shiny for default column values when new row added (#33)
+
+* Fixed bug that jumbled columns when some column names were numeric (#47, #52)
+
+* Fixed a bug in the validation logic that was preventing the call background from changing to red for invalid entries when allowInvalid = TRUE (#48)
+
+rhandsontable 0.2.1
+-------------------------
+
+* Added a new function, hot_context_menu, to better control right-click menu. The option to export to csv has been removed for now, but a new context_menu example has been added that shows how to enable the option. The example also shows how to enable the table search functionality (#38, #41).
+
+* Added a new comments parameter to rhandsontable to allow bulk comment specification.
+
+* Added a new shiny _comment callback to track changes to table comments. See the new rhandsontable_comment example for more details.
+
+* Added dateFormat to hot_col and allow passing additional column parameters. Future updates should hopefully allow more control over date formatting.
+
+* Fixed a table resize bug (#26)
+
+* Fixed hot_to_r to preserve original data classes when useTypes = FALSE (#39). See the rhandsontable_output example for more details.
+
+* Fixed shiny select callback to use 1-based indices (instead of JavaScripts 0-based indices).
+
+rhandsontable 0.2
+-------------------------
+
+* Added a project page at http://jrowen.github.io/rhandsontable
+
+* Upgraded to handsontable 0.16.1
+
+* Improved mapping between R classes and handsontable column types.  Numeric columns
+  in R are now mapped to numeric columns in the table, and factors are now
+  mapped as dropdown columns (#30).
+
+* Numeric columns are now formatted as '0' for integers and '0.00' for all other
+  numeric columns.  See http://http://numeraljs.com/ for more details on
+  formatting options.
+
+* Sparkline charts (http://omnipotent.net/jquery.sparkline/) can now be added to the
+  table.  See the project page for examples, and thanks to the sparkline package and
+  Ramnath Vaidyanathan for inspiration.  The sparkline chart width will be
+  set to fit within the specified column width.  The feature is still evolving, so
+  please pass along feedback.
+
+* Display NA values as blank cells in the table.  This requires changing colums with NA
+  values to character when displaying in handsontable and may require special handling
+  for Date and factor columns.  See the examples on the project page for more details.
+  Thanks to Melanie Bacou for the suggestion.
+
+* Added stretchH parameter to hot_table.
+
+* Fixed a bug where the table was not updated when resized.
+
+* Fixed a bug with row indices when sorting rows (#34)
+
+* Set overflow: auto and specified a default height = 400 in shiny (#21).
+
+rhandsontable 0.1
+-------------------------
+
+* Initial version.
diff --git a/R/editAddin.R b/R/editAddin.R
new file mode 100644
index 0000000..4505607
--- /dev/null
+++ b/R/editAddin.R
@@ -0,0 +1,138 @@
+#' Edit a Data Frame.
+#'
+#' Interactively edit a \code{data.frame} or \code{data.table}. The resulting
+#' code will be emitted as a call to reload the data from a temp RDS file.
+#'
+#' This addin can be used to interactively edit.
+#' The intended way to use this is as follows:
+#'
+#' 1. Highlight a symbol naming a \code{data.frame} or \code{data.table}
+#'    in your R session, e.g. \code{mtcars}.
+#' 2. Execute this addin, to interactively edit it.
+#'
+#' When you're done, the code performing this operation will be emitted
+#' at the cursor position.
+#'
+#' This function borrows heavily from \href{rstudio/addinexamples/subsetAddin}{https://github.com/rstudio/addinexamples/blob/master/R/subsetAddin.R}
+#'
+#' @export
+editAddin <- 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
+
+  # create a temp file
+  fname = gsub("\\\\", "/", tempfile())
+
+  # Generate UI for the gadget.
+  ui <- miniUI::miniPage(
+    miniUI::gadgetTitleBar("Edit a data.frame"),
+    miniUI::miniContentPanel(
+      stableColumnLayout(
+        shiny::textInput("data", "Data", value = defaultData),
+        shiny::radioButtons("outType", "Output type",
+                            choices = c("Update original data" = "update",
+                                        "Print updates to script (no update)" = "print")
+        )
+      ),
+      shiny::uiOutput("pending"),
+      rHandsontableOutput("hot")
+    )
+  )
+
+  # Server code for the gadget.
+  server <- function(input, output, session) {
+    values = shiny::reactiveValues()
+    setHot = function(x) values[["hot"]] = x
+
+    reactiveData <- shiny::reactive({
+
+      # Collect inputs.
+      dataString <- input$data
+
+      # 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)
+
+      data
+    })
+
+    output$pending <- shiny::renderUI({
+      data <- reactiveData()
+      if (isErrorMessage(data))
+        htmltools::h4(style = "color: #AA7732;", data$message)
+    })
+
+    output$hot <- renderRHandsontable({
+      data <- reactiveData()
+      if (isErrorMessage(data))
+        return(NULL)
+
+      if (is.null(input$hot))
+        DF = data
+      else
+        DF = hot_to_r(input$hot)
+
+      setHot(DF)
+      rhandsontable(DF) %>%
+        hot_table(highlightCol = TRUE, highlightRow = TRUE)
+    })
+
+    # Listen for 'done'.
+    shiny::observeEvent(input$done, {
+
+      if (input$outType == "print") {
+        rslt <- capture.output(dput(values[["hot"]]))
+        rstudioapi::insertText(Inf, paste0(input$data, " = ",
+                                           paste(rslt, collapse = "\n")))
+      } else {
+        if (nzchar(input$data) && !is.null(values[["hot"]])) {
+          saveRDS(values[["hot"]], fname)
+          code <- paste(input$data, " = readRDS('", fname, "')", sep = "")
+          rstudioapi::sendToConsole(code)
+        }
+      }
+
+      invisible(shiny::stopApp())
+    })
+  }
+
+  # Use a modal dialog as a viewr.
+  viewer <- shiny::dialogViewer("Edit", width = 1000, height = 800)
+  shiny::runGadget(ui, server, viewer = viewer)
+
+}
+
+# these functions come from rstudio/addinexamples
+stableColumnLayout <- function(...) {
+  dots <- list(...)
+  n <- length(dots)
+  width <- 12 / n
+  class <- sprintf("col-xs-%s col-md-%s", width, width)
+  shiny::fluidRow(
+    lapply(dots, function(el) {
+      shiny::div(class = class, el)
+    })
+  )
+}
+
+isErrorMessage <- function(object) {
+  inherits(object, "error_message")
+}
+
+errorMessage <- function(type, message) {
+  structure(
+    list(type = type, message = message),
+    class = "error_message"
+  )
+}
diff --git a/R/misc.R b/R/misc.R
new file mode 100644
index 0000000..b86eb41
--- /dev/null
+++ b/R/misc.R
@@ -0,0 +1,138 @@
+# Map R classes to handsontable.js types
+get_col_types = function(data) {
+  if (is.matrix(data))  {
+    types = rep(typeof(data), ncol(data))
+  } else if (is.data.frame(data)){
+    types = as.character(lapply(data, class))
+  } else{
+    stop("Unsupported object type: ", class(data), " Can't extract column types.")
+  }
+
+  types <- sapply(types, function(type) {
+    if (grepl("factor", type)) return("factor")
+
+    switch(type,
+           integer="integer",
+           double="numeric",
+           numeric="numeric",
+           character="text",
+           logical="checkbox",
+           Date="date",
+           "text")
+  })
+
+  as.character(types)
+}
+
+# Convert handsontable to R object
+toR = function(data, changes, params, ...) {
+  rClass = params$rClass
+  colHeaders = unlist(params$rColHeaders)
+  rowHeaders = unlist(params$rRowHeaders)
+  rColClasses = unlist(params$rColClasses)[colHeaders]
+
+  out = data
+
+  # copy/paste may add rows without firing an afterCreateRow event (still needed?)
+  # if (length(out) != length(rowHeaders))
+  #   changes$event = "afterCreateRow"
+
+  # remove spare empty rows; autofill fix (not working)
+  # if (!is.null(changes$source) && changes$source == "autofill") {
+  #   rm_inds = sapply(out, function(x) all(unlist(x) == "NA"))
+  #   rm_inds = suppressWarnings(min(which(diff(rm_inds) == -1)))
+  #   if (rm_inds != Inf)
+  #     out = out[-(length(out) - rm_inds + 1)]
+  # }
+
+  # pre-conversion updates; afterCreateCol moved to end of function
+  if (changes$event == "afterCreateRow") {
+    # rename to numeric index
+    rowHeaders = genRowHeaders(length(out))
+  } else if (changes$event == "afterRemoveRow") {
+    inds = seq(changes$ind + 1, length.out = changes$ct)
+    rowHeaders = rowHeaders[-inds]
+  } else if (changes$event == "afterRemoveCol") {
+    # colHeaders already reflects removal
+    if (!("matrix" %in% rClass)) {
+      inds = seq(changes$ind + 1, 1, length.out = changes$ct)
+      rColClasses = rColClasses[-inds]
+    }
+  }
+
+  # convert
+  if ("matrix" %in% rClass) {
+    nr = length(out)
+    out = unlist(out, recursive = FALSE)
+    # replace NULL with NA
+    out = unlist(lapply(out, function(x) if (is.null(x)) NA else x))
+    out = matrix(out, nrow = nr, byrow = TRUE)
+    class(out) = params$rColClasses
+  } else if ("data.frame" %in% rClass) {
+    nr = length(out)
+    out = unlist(out, recursive = FALSE)
+    # replace NULL with NA
+    out = unlist(lapply(out, function(x) if (is.null(x)) NA else x))
+    out = matrix(out, nrow = nr, byrow = TRUE)
+    out = colClasses(as.data.frame(out, stringsAsFactors = FALSE),
+                     rColClasses, params$columns, ...)
+  } else {
+    stop("Conversion not implemented: ", rClass)
+  }
+
+  # post-conversion updates
+  if (changes$event == "afterCreateRow") {
+    # default logical NA in data.frame to FALSE
+    if (!("matrix" %in% rClass)) {
+      inds_logical = which(rColClasses == "logical")
+      for (i in inds_logical)
+        out[[i]] = ifelse(is.na(out[[i]]), FALSE, out[[i]])
+    }
+  }
+
+  # copy/paste may add cols without firing an afterCreateCol event so check
+  #   header length;
+  if (ncol(out) != length(colHeaders))
+    colHeaders = genColHeaders(changes, colHeaders)
+
+  colnames(out) = colHeaders
+  rownames(out) = rowHeaders
+
+  if ("data.table" %in% rClass)
+    out = as(out, "data.table")
+
+  out
+}
+
+# Coerces data.frame columns to the specified classes
+# see http://stackoverflow.com/questions/9214819/supply-a-vector-to-classes-of-dataframe
+colClasses <- function(d, colClasses, cols, date_fmt = "%m/%d/%Y", ...) {
+  colClasses <- rep(colClasses, len=length(d))
+  for(i in seq_along(d))
+    d[[i]] = switch(
+      colClasses[i],
+      Date = as.Date(d[[i]], origin='1970-01-01',
+                     format = date_fmt),
+      POSIXct = as.POSIXct(d[[i]], origin='1970-01-01',
+                           format = date_fmt),
+      factor = factor(d[[i]],
+                      levels = c(unlist(cols[[i]]$source),
+                                 unique(d[[i]][!(d[[i]] %in% unlist(cols[[i]]$source))])),
+                      ordered = TRUE),
+      json = jsonlite::toJSON(d[[i]]),
+      as(d[[i]], colClasses[i]))
+  d
+}
+
+genColHeaders <- function(changes, colHeaders) {
+  ind_ct = length(which(grepl("V[0-9]{1,}", colHeaders)))
+  # create new column names
+  new_cols = paste0("V", changes$ct + ind_ct)
+  # insert into vector
+  inds = seq(changes$ind + 1, 1, length.out = changes$ct)
+  c(colHeaders, new_cols)[order(c(seq_along(colHeaders), inds - 0.5))]
+}
+
+genRowHeaders <- function(ct) {
+  seq_len(ct)
+}
diff --git a/R/rhandsontable-package.R b/R/rhandsontable-package.R
new file mode 100644
index 0000000..f57f25b
--- /dev/null
+++ b/R/rhandsontable-package.R
@@ -0,0 +1,26 @@
+#' rhandsontable
+#'
+#' R interface for creating tables using Handsontable, url{http://http://handsontable.com/}
+#'
+#' For full documentation on the package, visit \url{http://jrowen.github.io/rhandsontable/}
+#' @name rhandsontable-package
+#' @docType package
+#' @import htmlwidgets jsonlite
+#' @importFrom utils modifyList capture.output
+#' @importFrom methods as
+NULL
+
+#' rhandsontable exported operators
+#'
+#' The following functions are imported and then re-exported
+#' from the rhandsontable package to enable use of the magrittr
+#' pipe operator with no additional library calls
+#'
+#' @name rhandsontable-exports
+NULL
+
+#' @importFrom magrittr %>%
+#' @name %>%
+#' @export
+#' @rdname rhandsontable-exports
+NULL
diff --git a/R/rhandsontable.R b/R/rhandsontable.R
new file mode 100644
index 0000000..56f3406
--- /dev/null
+++ b/R/rhandsontable.R
@@ -0,0 +1,750 @@
+#' Handsontable widget
+#'
+#' Create a \href{http://handsontable.com}{Handsontable.js} widget.
+#'
+#' For full documentation on the package, visit \url{http://jrowen.github.io/rhandsontable/}
+#' @param data a \code{data.table}, \code{data.frame} or \code{matrix}
+#' @param colHeaders a vector of column names. If missing \code{colnames}
+#'  will be used. Setting to \code{NULL} will omit.
+#' @param rowHeaders a vector of row names. If missing \code{rownames}
+#'  will be used. Setting to \code{NULL} will omit.
+#' @param comments matrix or data.frame of comments; NA values are ignored
+#' @param useTypes logical specifying whether column classes should be mapped to
+#'  equivalent Javascript types.  Note that
+#'  Handsontable does not support column add/remove when column types
+#'  are defined (i.e. useTypes == TRUE in rhandsontable).
+#' @param readOnly logical specifying whether the table is editable
+#' @param selectCallback logical enabling the afterSelect event to return data.
+#'  This can be used with shiny to tie updates to a selected table cell.
+#' @param width numeric table width
+#' @param height numeric table height
+#' @param digits numeric passed to \code{jsonlite::toJSON}
+#' @param debug numeric Javascript log level
+#' @param ... passed to \code{hot_table} and to the \code{params} property of the widget
+#' @examples
+#' library(rhandsontable)
+#' DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+#'                 small = letters[1:10],
+#'                 dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+#'                 stringsAsFactors = FALSE)
+#'
+#' rhandsontable(DF, rowHeaders = NULL)
+#' @seealso \code{\link{hot_table}}, \code{\link{hot_cols}}, \code{\link{hot_rows}}, \code{\link{hot_cell}}
+#' @export
+rhandsontable <- function(data, colHeaders, rowHeaders, comments = NULL,
+                          useTypes = TRUE, readOnly = NULL,
+                          selectCallback = FALSE,
+                          width = NULL, height = NULL, digits = 4,
+                          debug = NULL, ...) {
+  rColHeaders = colnames(data)
+  rRowHeaders = rownames(data)
+
+  if (missing(colHeaders))
+    colHeaders = colnames(data)
+  if (missing(rowHeaders))
+    rowHeaders = rownames(data)
+
+  rClass = class(data)
+  if ("matrix" %in% rClass) {
+    rColClasses = class(data[1, 1])
+  } else {
+    rColClasses = lapply(data, class)
+    rColClasses[grepl("factor", rColClasses)] = "factor"
+  }
+
+  if (!useTypes) {
+    data = do.call(cbind, lapply(data, function(x) {
+      if (class(x) == "Date")
+        as.character(x, format = "%m/%d/%Y")
+      else
+        as.character(x)
+    }))
+    data = as.matrix(data, rownames.force = TRUE)
+    cols = NULL
+  } else {
+    # get column data types
+    col_typs = get_col_types(data)
+
+    # format date for display
+    dt_inds = which(col_typs == "date")
+    if (length(dt_inds) > 0L) {
+      for (i in dt_inds)
+        data[, i] = as.character(data[, i], format = "%m/%d/%Y")
+    }
+
+    cols = lapply(seq_along(col_typs), function(i) {
+      type = col_typs[i]
+      if (type == "factor") {
+#         data_fact = data.frame(level = levels(data[, i]),
+#                                label = labels(data[, i]))
+        res = list(type = "dropdown",
+                   source = levels(data[, i]),
+                   allowInvalid = FALSE
+#                    handsontable = list(
+#                      colHeaders = FALSE, #c("Label", "Level"),
+#                      data = levels(data[, i]) #jsonlite::toJSON(data_fact, na = "string",
+#                                               #rownames = FALSE)
+#                    )
+        )
+      } else if (type == "numeric") {
+        res = list(type = "numeric",
+                   format = "0.00")
+      } else if (type == "integer") {
+        res = list(type = "numeric",
+                   format = "0")
+      } else if (type == "date") {
+        res = list(type = "date",
+                   correctFormat = TRUE,
+                   dateFormat = "MM/DD/YYYY")
+      } else {
+        res = list(type = type)
+      }
+      res$readOnly = readOnly
+      res$renderer = JS("customRenderer")
+      res$default = NA
+      res
+    })
+  }
+
+  x = list(
+    data = jsonlite::toJSON(data, na = "string", rownames = FALSE,
+                            digits = digits),
+    rClass = rClass,
+    rColClasses = rColClasses,
+    rColnames = as.list(colnames(data)),
+    rColHeaders = rColHeaders,
+    rRowHeaders = rRowHeaders,
+    rDataDim = dim(data),
+    selectCallback = selectCallback,
+    colHeaders = colHeaders,
+    rowHeaders = rowHeaders,
+    columns = cols,
+    width = width,
+    height = height,
+    debug = ifelse(is.null(debug) || is.na(debug) || !is.numeric(debug), 0, debug)
+  )
+
+  # create widget
+  hot = htmlwidgets::createWidget(
+    name = 'rhandsontable',
+    x,
+    width = width,
+    height = height,
+    package = 'rhandsontable',
+    sizingPolicy = htmlwidgets::sizingPolicy(
+      padding = 5,
+      defaultHeight = "100%",
+      defaultWidth = "100%"
+    )
+  )
+
+  if (!is.null(readOnly)) {
+    for (x in hot$x$colHeaders)
+      hot = hot %>% hot_col(x, readOnly = readOnly)
+  }
+
+  hot = hot %>% hot_table(enableComments = !is.null(comments), ...)
+
+  if (!is.null(comments)) {
+    inds = as.data.frame(which(!is.na(comments), arr.ind = TRUE))
+    for (i in 1:nrow(inds))
+      hot = hot %>%
+        hot_cell(inds$row[i], inds$col[i],
+                 comment = comments[inds$row[i], inds$col[i]])
+    #hot$x$rComments = jsonlite::toJSON(comments)
+  }
+
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Configure table.  See
+#' \href{http://handsontable.com}{Handsontable.js} for details.
+#'
+#' @param hot rhandsontable object
+#' @param contextMenu logical enabling the right-click menu
+#' @param stretchH character describing column stretching. Options are 'all', 'right',
+#'  and 'none'. See \href{http://docs.handsontable.com/0.16.1/demo-stretching.html}{Column stretching} for details.
+#' @param customBorders json object. See
+#'  \href{http://handsontable.com/demo/custom_borders.html}{Custom borders} for details.
+#' @param highlightRow logical enabling row highlighting for the selected
+#'  cell
+#' @param highlightCol logical enabling column highlighting for the
+#'  selected cell
+#' @param enableComments logical enabling comments in the table
+#' @param overflow character setting the css overflow behavior. Options are
+#'  auto (default), hidden and visible
+#' @param rowHeaderWidth numeric width (in px) for the rowHeader column
+#' @param ... passed to \href{http://handsontable.com}{Handsontable.js} constructor
+#' @examples
+#' library(rhandsontable)
+#' DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+#'                 small = letters[1:10],
+#'                 dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+#'                 stringsAsFactors = FALSE)
+#'
+#' rhandsontable(DF) %>%
+#' hot_table(highlightCol = TRUE, highlightRow = TRUE)
+#' @seealso \code{\link{rhandsontable}}
+#' @export
+hot_table = function(hot, contextMenu = TRUE, stretchH = "none",
+                     customBorders = NULL, highlightRow = NULL,
+                     highlightCol = NULL, enableComments = FALSE,
+                     overflow = NULL, rowHeaderWidth = NULL, ...) {
+  if (!is.null(stretchH)) hot$x$stretchH = stretchH
+  if (!is.null(customBorders)) hot$x$customBorders = customBorders
+  if (!is.null(enableComments)) hot$x$comments = enableComments
+  if (!is.null(overflow)) hot$x$overflow = overflow
+  if (!is.null(rowHeaderWidth)) hot$x$rowHeaderWidth = rowHeaderWidth
+
+  if ((!is.null(highlightRow) && highlightRow) ||
+      (!is.null(highlightCol) && highlightCol))
+    hot$x$ishighlight = TRUE
+  if (!is.null(highlightRow) && highlightRow)
+    hot$x$currentRowClassName = "currentRow"
+  if (!is.null(highlightCol) && highlightCol)
+    hot$x$currentColClassName = "currentCol"
+
+  if (!is.null(contextMenu) && contextMenu)
+    hot = hot %>%
+      hot_context_menu(allowComments = enableComments,
+                       allowCustomBorders = !is.null(customBorders),
+                       allowColEdit = is.null(hot$x$columns), ...)
+  else
+    hot$x$contextMenu = FALSE
+
+  if (!is.null(list(...)))
+    hot$x = c(hot$x, list(...))
+
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Configure the options for the right-click context menu.  See
+#'  \href{http://docs.handsontable.com/0.16.1/demo-context-menu.html}{Context Menu} and
+#'  \href{http://swisnl.github.io/jQuery-contextMenu/docs.html}{jquery contextMenu}
+#'  for details.
+#'
+#' @param hot rhandsontable object
+#' @param allowRowEdit logical enabling row editing
+#' @param allowColEdit logical enabling column editing. Note that
+#'  Handsontable does not support column add/remove when column types
+#'  are defined (i.e. useTypes == TRUE in rhandsontable).
+#' @param allowReadOnly logical enabling read-only toggle
+#' @param allowComments logical enabling comments
+#' @param allowCustomBorders logical enabling custom borders
+#' @param customOpts list
+#' @param ... ignored
+#' @examples
+#' library(rhandsontable)
+#' DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+#'                 small = letters[1:10],
+#'                 dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+#'                 stringsAsFactors = FALSE)
+#'
+#' rhandsontable(DF) %>%
+#'   hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE)
+#' @export
+hot_context_menu = function(hot, allowRowEdit = TRUE, allowColEdit = TRUE,
+                            allowReadOnly = FALSE, allowComments = FALSE,
+                            allowCustomBorders = FALSE,
+                            customOpts = NULL, ...) {
+  if (!is.null(hot$x$contextMenu) && is.logical(hot$x$contextMenu) &&
+      !hot$x$contextMenu)
+    warning("The context menu was disabled but will be re-enabled (hot_context_menu)")
+
+  if (!is.null(hot$x$colums) && allowColEdit)
+    warning("Handsontable.js does not support column add/delete when column types ",
+            "are defined.  Set useTypes = FALSE in rhandsontable to enable column ",
+            "edits.")
+
+  if (is.null(hot$x$contextMenu$items))
+    opts = list()
+  else
+    opts = hot$x$contextMenu$items
+
+  add_opts = function(new, old, val = list()) {
+    new_ = lapply(new, function(x) {
+      if (grepl("^hsep", x) && !is.null(val))
+        return(list(name = "---------"))
+      else
+        return(val)
+    })
+    names(new_) = new
+    if (length(old) > 0) {
+      modifyList(old, new_)
+    } else {
+      new_
+    }
+  }
+  remove_opts = function(new) {
+    add_opts(new, opts, val = NULL)
+  }
+
+  if (!is.null(allowRowEdit) && allowRowEdit)
+    opts =  add_opts(c("hsep1", "row_above", "row_below", "remove_row"), opts)
+  else
+    opts =  remove_opts(c("hsep1", "row_above", "row_below", "remove_row"))
+
+  if (!is.null(allowColEdit) && allowColEdit)
+    opts = add_opts(c("hsep2", "col_left", "col_right", "remove_col"), opts)
+  else
+    opts =  remove_opts(c("hsep2", "col_left", "col_right", "remove_col"))
+
+  opts = add_opts(c("hsep3", "undo", "redo"), opts)
+
+  opts = add_opts(c("hsep4", "alignment"), opts)
+
+  if (!is.null(allowReadOnly) && allowReadOnly)
+    opts = add_opts(c("hsep5", "make_read_only"), opts)
+  else
+    opts =  remove_opts(c("hsep5", "make_read_only"))
+
+  if (!is.null(allowComments) && allowComments)
+    opts = add_opts(c("hsep6", "commentsAddEdit", "commentsRemove"), opts)
+  else
+    opts =  remove_opts(c("hsep6", "commentsAddEdit", "commentsRemove"))
+
+  if (!is.null(allowCustomBorders) && allowCustomBorders)
+    opts = add_opts(c("hsep7", "borders"), opts)
+  else
+    opts =  remove_opts(c("hsep7", "borders"))
+
+  sep_ct = 20
+  if (!is.null(customOpts)) {
+    opts[[paste0("hsep", sep_ct)]] = list(name = "---------")
+    sep_ct = sep_ct + 1
+    opts = modifyList(opts, customOpts)
+  }
+
+  if (grepl("^hsep", names(opts)[1]))
+    opts = opts[-1]
+  if (grepl("^hsep", names(opts)[length(opts)]))
+    opts = opts[-length(opts)]
+
+  hot$x$contextMenu = list(items = opts)
+
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Configure multiple columns.
+#'
+#' @param hot rhandsontable object
+#' @param colWidths a scalar or numeric vector of column widths
+#' @param columnSorting logical enabling row sorting. Sorting only alters the
+#'  table presentation and the original dataset row order is maintained.
+#'  The sorting will be done when a user click on column name
+#' @param manualColumnMove logical enabling column drag-and-drop reordering
+#' @param manualColumnResize logical enabline column width resizing
+#' @param fixedColumnsLeft a numeric vector indicating which columns should be
+#'  frozen on the left
+#' @param ... passed to hot_col
+#' @examples
+#' library(rhandsontable)
+#' DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+#'                 small = letters[1:10],
+#'                 dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+#'                 stringsAsFactors = FALSE)
+#'
+#' rhandsontable(DF) %>%
+#'   hot_cols(columnSorting = TRUE)
+#' @seealso \code{\link{hot_col}}, \code{\link{hot_rows}}, \code{\link{hot_cell}}
+#' @export
+hot_cols = function(hot, colWidths = NULL, columnSorting = NULL,
+                    manualColumnMove = NULL, manualColumnResize = NULL,
+                    fixedColumnsLeft = NULL, ...) {
+  if (!is.null(colWidths)) hot$x$colWidths = colWidths
+
+  if (!is.null(columnSorting)) hot$x$columnSorting = columnSorting
+  if (!is.null(manualColumnMove)) hot$x$manualColumnMove = manualColumnMove
+  if (!is.null(manualColumnResize)) hot$x$manualColumnResize = manualColumnResize
+
+  if (!is.null(fixedColumnsLeft)) hot$x$fixedColumnsLeft = fixedColumnsLeft
+
+  for (i in seq_len(length(hot$x$columns)))
+    hot = hot %>% hot_col(i, ...)
+
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Configure single column.
+#'
+#' @param hot rhandsontable object
+#' @param col vector of column names or indices
+#' @param type character specify the data type. Options include:
+#'  numeric, date, checkbox, select, dropdown, autocomplete, password,
+#'  and handsontable (not implemented yet)
+#' @param format characer specifying column format. See Cell Types at
+#'  \href{http://handsontable.com}{Handsontable.js} for the formatting
+#'  options for each data type. Numeric columns are formatted using
+#'  \href{http://numeraljs.com}{Numeral.js}.
+#' @param source a vector of choices for select, dropdown and autocomplete
+#'  column types
+#' @param strict logical specifying whether values not in the \code{source}
+#'  vector will be accepted
+#' @param readOnly logical making the table read-only
+#' @param validator character defining a Javascript function to be used
+#'  to validate user input. See \code{hot_validate_numeric} and
+#'  \code{hot_validate_character} for pre-build validators.
+#' @param allowInvalid logical specifying whether invalid data will be
+#'  accepted. Invalid data cells will be color red.
+#' @param halign character defining the horizontal alignment. Possible
+#'  values are htLeft, htCenter, htRight and htJustify
+#' @param valign character defining the vertical alignment. Possible
+#'  values are htTop, htMiddle, htBottom
+#' @param renderer character defining a Javascript function to be used
+#'  to format column cells. Can be used to implement conditional formatting.
+#' @param copyable logical defining whether data in a cell can be copied using
+#'  Ctrl + C
+#' @param dateFormat character defining the date format. See
+#'  \href{https://github.com/moment/moment}{Moment.js} for details.
+#' @param default default column value for new rows (NA if not specified; shiny only)
+#' @param language locale passed to \href{http://numbrojs.com}{Numbro.js};
+#'  default is 'en-US'.
+#' @param ... passed to handsontable
+#' @examples
+#' library(rhandsontable)
+#' DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+#'                 small = letters[1:10],
+#'                 dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+#'                 stringsAsFactors = FALSE)
+#'
+#' rhandsontable(DF, rowHeaders = NULL) %>%
+#'   hot_col(col = "big", type = "dropdown", source = LETTERS) %>%
+#'   hot_col(col = "small", type = "autocomplete", source = letters,
+#'           strict = FALSE)
+#' @seealso \code{\link{hot_cols}}, \code{\link{hot_rows}}, \code{\link{hot_cell}}
+#' @export
+hot_col = function(hot, col, type = NULL, format = NULL, source = NULL,
+                   strict = NULL, readOnly = NULL, validator = NULL,
+                   allowInvalid = NULL, halign = NULL, valign = NULL,
+                   renderer = NULL, copyable = NULL, dateFormat = NULL,
+                   default = NULL, language = NULL, ...) {
+  cols = hot$x$columns
+  if (is.null(cols)) {
+    # create a columns list
+    warning("rhandsontable column types were previously not defined but are ",
+            "now being set to 'text' to support column properties")
+    cols = lapply(hot$x$colHeaders, function(x) {
+      list(type = "text")
+    })
+  }
+
+  for (i in col) {
+    if (is.character(i)) i = which(hot$x$colHeaders == i)
+
+    if (!is.null(type)) cols[[i]]$type = type
+    if (!is.null(format)) cols[[i]]$format = format
+    if (!is.null(dateFormat)) cols[[i]]$dateFormat = dateFormat
+    if (!is.null(source)) cols[[i]]$source = source
+    if (!is.null(strict)) cols[[i]]$strict = strict
+    if (!is.null(readOnly)) cols[[i]]$readOnly = readOnly
+    if (!is.null(copyable)) cols[[i]]$copyable = copyable
+    if (!is.null(default)) cols[[i]]$default = default
+    if (!is.null(language)) cols[[i]]$language = language
+
+    if (!is.null(validator)) cols[[i]]$validator = JS(validator)
+    if (!is.null(allowInvalid)) cols[[i]]$allowInvalid = allowInvalid
+    if (!is.null(renderer)) cols[[i]]$renderer = JS(renderer)
+
+    if (!is.null(list(...)))
+      cols[[i]] = c(cols[[i]], list(...))
+
+    className = c(halign, valign)
+    if (!is.null(className)) {
+      cols[[i]]$className = className
+    }
+  }
+
+  hot$x$columns = cols
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Configure rows.  See
+#' \href{http://handsontable.com}{Handsontable.js} for details.
+#'
+#' @param hot rhandsontable object
+#' @param rowHeights a scalar or numeric vector of row heights
+#' @param fixedRowsTop a numeric vector indicating which rows should be
+#'  frozen on the top
+#' @examples
+#' library(rhandsontable)
+#' MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+#'              letters[1:5]))
+#'
+#' rhandsontable(MAT, width = 300, height = 150) %>%
+#' hot_cols(colWidths = 100, fixedColumnsLeft = 1) %>%
+#'   hot_rows(rowHeights = 50, fixedRowsTop = 1)
+#' @seealso \code{\link{hot_cols}}, \code{\link{hot_cell}}
+#' @export
+hot_rows = function(hot, rowHeights = NULL, fixedRowsTop = NULL) {
+  if (!is.null(rowHeights)) hot$x$rowHeights = rowHeights
+  if (!is.null(fixedRowsTop)) hot$x$fixedRowsTop = fixedRowsTop
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Configure single cell.  See
+#' \href{http://handsontable.com}{Handsontable.js} for details.
+#'
+#' @param hot rhandsontable object
+#' @param row numeric row index
+#' @param col numeric column index
+#' @param comment character comment to add to cell
+#' @examples
+#' library(rhandsontable)
+#' DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+#'                 small = letters[1:10],
+#'                 dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+#'                 stringsAsFactors = FALSE)
+#'
+#' rhandsontable(DF, readOnly = TRUE) %>%
+#'   hot_cell(1, 1, "Test comment")
+#' @seealso \code{\link{hot_cols}}, \code{\link{hot_rows}}
+#' @export
+hot_cell = function(hot, row, col, comment = NULL) {
+  cell = list(row = row - 1, col = col - 1, comment = comment)
+
+  hot$x$cell = c(hot$x$cell, list(cell))
+
+  hot = hot %>% hot_table(enableComments = TRUE)
+#   if (is.null(hot$x$rComments)) {
+#     cmts = matrix(nrow = hot$x$rDataDim[1], ncol = hot$x$rDataDim[2])
+#   } else {
+#     cmts = jsonlite::fromJSON(hot$x$rComments)
+#   }
+#   cmts[row, col] = comment
+#   hot$x$rComments = jsonlite::toJSON(cmts)
+
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Add numeric validation to a column
+#'
+#' @param hot rhandsontable object
+#' @param cols vector of column names or indices
+#' @param min minimum value to accept
+#' @param max maximum value to accept
+#' @param choices a vector of acceptable numeric choices. It will be evaluated
+#'  after min and max if specified.
+#' @param exclude a vector of unacceptable numeric values
+#' @param allowInvalid logical specifying whether invalid data will be
+#'  accepted. Invalid data cells will be color red.
+#' @examples
+#' library(rhandsontable)
+#' MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+#'              letters[1:5]))
+#'
+#' rhandsontable(MAT * 10) %>%
+#'   hot_validate_numeric(col = 1, min = -50, max = 50, exclude = 40)
+#'
+#' rhandsontable(MAT * 10) %>%
+#'   hot_validate_numeric(col = 1, choices = c(10, 20, 40))
+#' @seealso \code{\link{hot_validate_character}}
+#' @export
+hot_validate_numeric = function(hot, cols, min = NULL, max = NULL,
+                                choices = NULL, exclude = NULL,
+                                allowInvalid = FALSE) {
+  f = "function (value, callback) {
+         setTimeout(function(){
+           if (isNaN(parseFloat(value))) {
+             callback(false);
+           }
+           %exclude
+           %min
+           %max
+           %choices
+           return callback(true);
+         }, 500)
+       }"
+
+  if (!is.null(exclude))
+    ex_str = paste0("if ([",
+                    paste0(paste0("'", exclude, "'"), collapse = ","),
+                    "].indexOf(value) > -1) { return callback(false); }")
+  else
+    ex_str = ""
+  f = gsub("%exclude", ex_str, f)
+
+  if (!is.null(min))
+    min_str = paste0("if (value < ", min, ") { return callback(false); }")
+  else
+    min_str = ""
+  f = gsub("%min", min_str, f)
+
+  if (!is.null(max))
+    max_str = paste0("if (value > ", max, ") { return callback(false); }")
+  else
+    max_str = ""
+  f = gsub("%max", max_str, f)
+
+  if (!is.null(choices))
+    chcs_str = paste0("if ([",
+                      paste0(paste0("'", choices, "'"), collapse = ","),
+                      "].indexOf(value) == -1) { return callback(false); }")
+  else
+    chcs_str = ""
+  f = gsub("%choices", chcs_str, f)
+
+  for (x in cols)
+    hot = hot %>% hot_col(x, validator = f,
+                          allowInvalid = allowInvalid)
+
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Add numeric validation to a column
+#'
+#' @param hot rhandsontable object
+#' @param cols vector of column names or indices
+#' @param choices a vector of acceptable numeric choices. It will be evaluated
+#'  after min and max if specified.
+#' @param allowInvalid logical specifying whether invalid data will be
+#'  accepted. Invalid data cells will be color red.
+#' @examples
+#' library(rhandsontable)
+#' DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+#'                 small = letters[1:10],
+#'                 dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+#'                 stringsAsFactors = FALSE)
+#'
+#' rhandsontable(DF) %>%
+#'   hot_validate_character(col = "big", choices = LETTERS[1:10])
+#' @seealso \code{\link{hot_validate_numeric}}
+#' @export
+hot_validate_character = function(hot, cols, choices,
+                                  allowInvalid = FALSE) {
+  f = "function (value, callback) {
+         setTimeout(function() {
+           if (typeof(value) != 'string') {
+             return callback(false);
+           }
+           %choices
+           return callback(false);
+         }, 500)
+       }"
+
+  ch_str = paste0("if ([",
+                  paste0(paste0("'", choices, "'"), collapse = ","),
+                  "].indexOf(value) > -1) { return callback(true); }")
+  f = gsub("%choices", ch_str, f)
+
+  for (x in cols)
+    hot = hot %>% hot_col(x, validator = f,
+                          allowInvalid = allowInvalid)
+
+  hot
+}
+
+#' Handsontable widget
+#'
+#' Add heatmap to table.  See
+#' \href{http://docs.handsontable.com/0.16.1/demo-chromajs.html}{Heatmaps for values in a column}
+#' for details.
+#'
+#' @param hot rhandsontable object
+#' @param cols numeric vector of columns to include in the heatmap. If missing
+#'  all columns are used.
+#' @param color_scale character vector that includes the lower and upper
+#'  colors
+#' @param renderer character defining a Javascript function to be used
+#'  to determine the cell colors. If missing,
+#'  \code{rhandsontable:::renderer_heatmap} is used.
+#' @examples
+#' MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+#'              letters[1:5]))
+#'
+#'rhandsontable(MAT) %>%
+#'  hot_heatmap()
+#' @export
+hot_heatmap = function(hot, cols, color_scale = c("#ED6D47", "#17F556"),
+                       renderer = NULL) {
+  hot$x$isHeatmap = TRUE
+
+  if (is.null(renderer)) {
+    renderer = renderer_heatmap(color_scale)
+  }
+
+  if (missing(cols))
+    cols = seq_along(hot$x$colHeaders)
+  for (x in hot$x$colHeaders[cols])
+    hot = hot %>% hot_col(x, renderer = renderer)
+
+  hot
+}
+
+# Used by hot_heatmap
+renderer_heatmap = function(color_scale) {
+  renderer = gsub("\n", "", "
+      function (instance, td, row, col, prop, value, cellProperties) {
+
+        Handsontable.renderers.TextRenderer.apply(this, arguments);
+        heatmapScale  = chroma.scale(['%s1', '%s2']);
+
+        if (instance.heatmap[col]) {
+          mn = instance.heatmap[col].min;
+          mx = instance.heatmap[col].max;
+          pt = (parseInt(value, 10) - mn) / (mx - mn);
+
+          td.style.backgroundColor = heatmapScale(pt).hex();
+        }
+      }
+      ")
+  renderer = gsub("%s1", color_scale[1], renderer)
+  renderer = gsub("%s2", color_scale[2], renderer)
+  renderer
+}
+
+#' Handsontable widget
+#'
+#' Shiny bindings for rhandsontable
+#'
+#' @param outputId output variable to read from
+#' @param width,height must be a valid CSS unit in pixels
+#'  or a number, which will be coerced to a string and have \code{"px"} appended.
+#' @seealso \code{\link{renderRHandsontable}}
+#' @export
+rHandsontableOutput <- function(outputId, width = "100%", height = "100%"){
+  htmlwidgets::shinyWidgetOutput(outputId, 'rhandsontable', width, height,
+                                 package = 'rhandsontable')
+}
+
+#' Handsontable widget
+#'
+#' Shiny bindings for rhandsontable
+#'
+#' @param expr an expression that generates an rhandsontable.
+#' @param env the environment in which to evaluate \code{expr}.
+#' @param quoted is \code{expr} a quoted expression (with \code{quote()})? This
+#'  is useful if you want to save an expression in a variable.
+#' @seealso \code{\link{rHandsontableOutput}}, \code{\link{hot_to_r}}
+#' @export
+renderRHandsontable <- function(expr, env = parent.frame(), quoted = FALSE) {
+  if (!quoted) { expr <- substitute(expr) } # force quoted
+  htmlwidgets::shinyRenderWidget(expr, rHandsontableOutput, env, quoted = TRUE)
+}
+
+#' Handsontable widget
+#'
+#' Convert handsontable data to R object. Can be used in a \code{shiny} app
+#'  to convert the input json to an R dataset.
+#'
+#' @param ... passed to \code{rhandsontable:::toR}
+#' @seealso \code{\link{rHandsontableOutput}}
+#' @export
+hot_to_r = function(...) {
+  do.call(toR, ...)
+}
diff --git a/build/vignette.rds b/build/vignette.rds
new file mode 100644
index 0000000..b18e5b5
Binary files /dev/null and b/build/vignette.rds differ
diff --git a/inst/doc/intro_rhandsontable.R b/inst/doc/intro_rhandsontable.R
new file mode 100644
index 0000000..69d582c
--- /dev/null
+++ b/inst/doc/intro_rhandsontable.R
@@ -0,0 +1,381 @@
+## ----echo = FALSE--------------------------------------------------------
+library(rhandsontable)
+library(knitr)
+
+opts_knit$set(warning = FALSE, error = FALSE, message = FALSE, cache = FALSE,
+              fig.width=7, fig.height=3)
+
+## ------------------------------------------------------------------------
+DF = data.frame(integer = 1:10,
+                   numeric = rnorm(10),
+                   logical = rep(TRUE, 10), 
+                   character = LETTERS[1:10],
+                   factor = factor(letters[1:10], levels = letters[10:1], 
+                                   ordered = TRUE),
+                   factor_allow = factor(letters[1:10], levels = letters[10:1], 
+                                         ordered = TRUE),
+                   date = seq(from = Sys.Date(), by = "days", length.out = 10),
+                   stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 600, height = 300) %>%
+  hot_col("factor_allow", allowInvalid = TRUE)
+
+## ------------------------------------------------------------------------
+DF_na = data.frame(integer = c(NA, 2:10), 
+                   logical = c(NA, rep(TRUE, 9)), 
+                   character = c(NA, LETTERS[1:9]),
+                   factor = c(NA, factor(letters[1:9])),
+                   date = c(NA, seq(from = Sys.Date(), by = "days", 
+                                    length.out = 9)),
+                   stringsAsFactors = FALSE)
+
+DF_na$factor_ch = as.character(DF_na$factor)
+DF_na$date_ch = c(NA, as.character(seq(from = Sys.Date(), by = "days", 
+                                       length.out = 9)))
+
+rhandsontable(DF_na, width = 550, height = 300)
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+# try updating big to a value not in the dropdown
+rhandsontable(DF, rowHeaders = NULL, width = 550, height = 300) %>%
+  hot_col(col = "big", type = "dropdown", source = LETTERS) %>%
+  hot_col(col = "small", type = "autocomplete", source = letters,
+          strict = FALSE)
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_col("small", "password")
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+DF$chart = c(sapply(1:5,
+                    function(x) jsonlite::toJSON(list(values=rnorm(10),
+                                                      options = list(type = "bar")))),
+             sapply(1:5,
+                    function(x) jsonlite::toJSON(list(values=rnorm(10),
+                                                      options = list(type = "line")))))
+
+rhandsontable(DF, rowHeaders = NULL, width = 550, height = 300) %>%
+  hot_col("chart", renderer = htmlwidgets::JS("renderSparkline"))
+
+## ----fig.height = 5, fig.width = 8---------------------------------------
+DF = data.frame(
+  title = c(
+    "<a href='http://www.amazon.com/Professional-JavaScript-Developers-Nicholas-Zakas/dp/1118026691'>Professional JavaScript for Web Developers</a>",
+    "<a href='http://shop.oreilly.com/product/9780596517748.do'>JavaScript: The Good Parts</a>",
+    "<a href='http://shop.oreilly.com/product/9780596805531.do'>JavaScript: The Definitive Guide</a>"
+  ),
+  desc = c(
+    "This <a href='http://bit.ly/sM1bDf'>book</a> provides a developer-level introduction along with more advanced and useful features of <b>JavaScript</b>.",
+    "This book provides a developer-level introduction along with <b>more advanced</b> and useful features of JavaScript.",
+    "<em>JavaScript: The Definitive Guide</em> provides a thorough description of the core <b>JavaScript</b> language and both the legacy and standard DOMs implemented in web browsers."
+  ),
+  comments = c(
+    "I would rate it &#x2605;&#x2605;&#x2605;&#x2605;&#x2606;",
+    "This is the book about JavaScript",
+    "I've never actually read it, but the <a href='http://shop.oreilly.com/product/9780596805531.do'>comments</a> are highly <strong>positive</strong>."
+  ), 
+  cover = c(
+    "http://ecx.images-amazon.com/images/I/51bRhyVTVGL._SL50_.jpg",
+    "http://ecx.images-amazon.com/images/I/51gdVAEfPUL._SL50_.jpg",
+    "http://ecx.images-amazon.com/images/I/51VFNL4T7kL._SL50_.jpg"
+ ),
+ stringsAsFactors = FALSE
+)
+
+rhandsontable(DF, allowedTags = "<em><b><strong><a><big>", 
+              width = 800, height = 450, rowHeaders = FALSE) %>%
+  hot_cols(colWidths = c(200, 200, 200, 80)) %>%
+  hot_col(1:2, renderer = "html") %>%
+  hot_col(1:3, renderer = htmlwidgets::JS("safeHtmlRenderer")) %>%
+  hot_col(4, renderer = "
+    function(instance, td, row, col, prop, value, cellProperties) {
+      var escaped = Handsontable.helper.stringify(value),
+        img;
+  
+      if (escaped.indexOf('http') === 0) {
+        img = document.createElement('IMG');
+        img.src = value;
+  
+        Handsontable.Dom.addEvent(img, 'mousedown', function (e){
+          e.preventDefault(); // prevent selection quirk
+        });
+  
+        Handsontable.Dom.empty(td);
+        td.appendChild(img);
+      }
+      else {
+        // render as text
+        Handsontable.renderers.TextRenderer.apply(this, arguments);
+      }
+  
+      return td;
+    }")
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+col_highlight = 2
+row_highlight = c(5, 7)
+
+rhandsontable(DF, col_highlight = col_highlight, 
+              row_highlight = row_highlight,
+              width = 550, height = 300) %>%
+  hot_cols(renderer = "
+    function(instance, td, row, col, prop, value, cellProperties) {
+      Handsontable.TextCell.renderer.apply(this, arguments);
+      
+      tbl = this.HTMLWidgets.widgets[0]
+
+      hcols = tbl.params.col_highlight
+      hcols = hcols instanceof Array ? hcols : [hcols] 
+      hrows = tbl.params.row_highlight
+      hrows = hrows instanceof Array ? hrows : [hrows] 
+
+      if (hcols.includes(col) && hrows.includes(row)) {
+        td.style.background = 'red';
+      }
+      else if (hcols.includes(col)) {
+        td.style.background = 'lightgreen';
+      }
+      else if (hrows.includes(row)) {
+        td.style.background = 'pink';
+      }
+      
+      return td;
+  }")
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE)
+
+## ------------------------------------------------------------------------
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_context_menu(
+    customOpts = list(
+      csv = list(name = "Download to CSV",
+                    callback = htmlwidgets::JS(
+                      "function (key, options) {
+                         var csv = csvString(this);
+
+                         var link = document.createElement('a');
+                         link.setAttribute('href', 'data:text/plain;charset=utf-8,' +
+                           encodeURIComponent(csv));
+                         link.setAttribute('download', 'data.csv');
+
+                         document.body.appendChild(link);
+                         link.click();
+                         document.body.removeChild(link);
+                       }"))))
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10,
+                bool = TRUE,
+                big = LETTERS[1:10],
+                small = factor(letters[1:10]),
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, search = TRUE, width = 550, height = 300) %>%
+  hot_context_menu(
+    customOpts = list(
+      search = list(name = "Search",
+                    callback = htmlwidgets::JS(
+                      "function (key, options) {
+                         var srch = prompt('Search criteria');
+
+                         this.search.query(srch);
+                         this.render();
+                       }"))))
+
+## ------------------------------------------------------------------------
+DF = data.frame(int = 1:10, float = rnorm(10), cur = rnorm(10) * 1E5,
+                lrg = rnorm(10) * 1E8, pct = rnorm(10))
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_col("float", format = "0.0") %>%
+  hot_col("cur", format = "$0,0.00") %>%
+  hot_col("lrg", format = "0a") %>%
+  hot_col("pct", format = "0%")
+
+## ------------------------------------------------------------------------
+DF = data.frame(dollar = rnorm(10), euro = rnorm(10), yen = rnorm(10))
+
+rhandsontable(DF * 1000, width = 550, height = 300) %>%
+  hot_col("dollar", format = "$0,000.00", language = "en-US") %>%
+  hot_col("euro", format = "0,000.00 $", language = "de-DE") %>%
+  hot_col("yen", format = "$0,000.00", language = "ja-JP")
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, readOnly = TRUE, width = 550, height = 300) %>%
+  hot_col("val", readOnly = FALSE)
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_cols(columnSorting = TRUE)
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+# click on a cell to see the highlighting
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_table(highlightCol = TRUE, highlightRow = TRUE)
+
+## ----fig.height = 6, fig.width = 6---------------------------------------
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 600, height = 600) %>%
+  hot_cols(colWidths = 100) %>%
+  hot_rows(rowHeights = 50)
+
+## ----fig.height = 6, fig.width = 6---------------------------------------
+rhandsontable(mtcars, rowHeaderWidth = 200)
+
+## ----fig.height = 6, fig.width = 6---------------------------------------
+MAT = matrix(rnorm(30), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:3]))
+
+rhandsontable(MAT, width = 600, height = 300, stretchH = "all")
+
+## ------------------------------------------------------------------------
+MAT = matrix(rnorm(26 * 26), nrow = 26, dimnames = list(LETTERS, letters))
+
+# scroll through the table to see the fixed row and column
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_cols(fixedColumnsLeft = 1) %>%
+  hot_rows(fixedRowsTop = 1)
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_cell(1, 1, "Test comment")
+
+## ------------------------------------------------------------------------
+MAT_comments = matrix(ncol = ncol(DF), nrow = nrow(DF))
+MAT_comments[1, 1] = "Test comment"
+MAT_comments[2, 2] = "Another test comment"
+
+rhandsontable(DF, comments = MAT_comments, width = 550, height = 300)
+
+## ------------------------------------------------------------------------
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_table(customBorders = list(list(
+    range = list(from = list(row = 1, col = 1),
+                 to = list(row = 2, col = 2)),
+    top = list(width = 2, color = "red"),
+    left = list(width = 2, color = "red"),
+    bottom = list(width = 2, color = "red"),
+    right = list(width = 2, color = "red"))))
+
+## ------------------------------------------------------------------------
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_validate_numeric(col = 1, min = -50, max = 50, exclude = 40)
+
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_validate_numeric(col = 1, choices = c(10, 20, 40))
+
+## ------------------------------------------------------------------------
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_validate_character(col = "big", choices = LETTERS[1:10])
+
+## ------------------------------------------------------------------------
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+# try to update any cell to 0
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_cols(validator = "
+           function (value, callback) {
+            setTimeout(function(){
+              callback(value != 0);
+            }, 1000)
+           }",
+           allowInvalid = FALSE)
+
+## ---- fig.width = 8------------------------------------------------------
+MAT = matrix(runif(100, -1, 1), nrow = 10,
+             dimnames = list(LETTERS[1:10], LETTERS[1:10]))
+diag(MAT) = 1
+MAT[upper.tri(MAT)] = MAT[lower.tri(MAT)]
+rhandsontable(MAT, readOnly = TRUE, width = 750, height = 300) %>%
+  hot_cols(renderer = "
+           function (instance, td, row, col, prop, value, cellProperties) {
+             Handsontable.renderers.TextRenderer.apply(this, arguments);
+             if (row == col) {
+              td.style.background = 'lightgrey';
+             } else if (col > row) {
+              td.style.background = 'grey';
+              td.style.color = 'grey';
+             } else if (value < -0.75) {
+              td.style.background = 'pink';
+             } else if (value > 0.75) {
+              td.style.background = 'lightgreen';
+             }
+           }")
+
+## ------------------------------------------------------------------------
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_heatmap()
+
+## ------------------------------------------------------------------------
+MAT = matrix(rnorm(10000 * 100), nrow = 100, dimnames= list(1:100, 1:10000))
+
+rhandsontable(MAT, width = 550, height = 550)
+
diff --git a/inst/doc/intro_rhandsontable.Rmd b/inst/doc/intro_rhandsontable.Rmd
new file mode 100644
index 0000000..8040299
--- /dev/null
+++ b/inst/doc/intro_rhandsontable.Rmd
@@ -0,0 +1,620 @@
+---
+title: "rhandsontable Introduction"
+author: "Jonathan Owen"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{rhandsontable Introduction}
+  %\VignetteEngine{knitr::rmarkdown}
+  \usepackage[utf8]{inputenc}
+---
+
+```{r echo = FALSE}
+library(rhandsontable)
+library(knitr)
+
+opts_knit$set(warning = FALSE, error = FALSE, message = FALSE, cache = FALSE,
+              fig.width=7, fig.height=3)
+```
+
+## Introduction
+
+  rhandsontable is a htmlwidget based on the [handsontable.js](https://www.handsontable.com) library.
+
+> Handsontable is a data grid component with an Excel-like appearance. Built in JavaScript, it integrates with any data source with peak efficiency. It comes with powerful features like data validation, sorting, grouping, data binding, formula support or column ordering.
+([via](https://www.handsontable.com))
+
+## Column Types
+
+The table includes support for numeric, logical, character and Date types.  Logical values will appear as check boxes, and the [pikaday.js](https://github.com/dbushell/Pikaday) library is used to specify Date values.
+
+rhandsontable attempts to map R classes to an appropriate handsontable type.  Factors will be mapped to `dropdown`, with the choices specified by `level` and `allowInvalid` set to `FALSE`.  To allow new levels, set `allowInvalid` to `TRUE` (using `hot_col`; it may also be desirable to set `strict` to `FALSE`).  When running in `shiny`, using `hot_to_r` will preserve custom factor ordering, and if new levels are allowed, they will be added to the end.
+
+```{r}
+DF = data.frame(integer = 1:10,
+                   numeric = rnorm(10),
+                   logical = rep(TRUE, 10), 
+                   character = LETTERS[1:10],
+                   factor = factor(letters[1:10], levels = letters[10:1], 
+                                   ordered = TRUE),
+                   factor_allow = factor(letters[1:10], levels = letters[10:1], 
+                                         ordered = TRUE),
+                   date = seq(from = Sys.Date(), by = "days", length.out = 10),
+                   stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 600, height = 300) %>%
+  hot_col("factor_allow", allowInvalid = TRUE)
+```
+
+To improve readability, `NA` values will be displayed as blank cells.  This requires converting columns containing `NA` to characters, and in the case of factors and Dates, may not display the data in the desired format.  It may be beneficial to concert these type of columns to character before passing to `rhandsontable`.
+
+```{r}
+DF_na = data.frame(integer = c(NA, 2:10), 
+                   logical = c(NA, rep(TRUE, 9)), 
+                   character = c(NA, LETTERS[1:9]),
+                   factor = c(NA, factor(letters[1:9])),
+                   date = c(NA, seq(from = Sys.Date(), by = "days", 
+                                    length.out = 9)),
+                   stringsAsFactors = FALSE)
+
+DF_na$factor_ch = as.character(DF_na$factor)
+DF_na$date_ch = c(NA, as.character(seq(from = Sys.Date(), by = "days", 
+                                       length.out = 9)))
+
+rhandsontable(DF_na, width = 550, height = 300)
+```
+
+### Dropdown / Autocomplete
+
+To control character column values, the column type can be specified as `dropdown` or `autocomplete`.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+# try updating big to a value not in the dropdown
+rhandsontable(DF, rowHeaders = NULL, width = 550, height = 300) %>%
+  hot_col(col = "big", type = "dropdown", source = LETTERS) %>%
+  hot_col(col = "small", type = "autocomplete", source = letters,
+          strict = FALSE)
+```
+
+### Password
+
+A column can also be specified as a `password` type.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_col("small", "password")
+```
+
+### Sparkline
+
+New in version 0.2, [sparkline.js](http://omnipotent.net/jquery.sparkline/) charts can be added to the table.  Thanks to the sparkline package and Ramnath Vaidyanathan for inspiration.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+DF$chart = c(sapply(1:5,
+                    function(x) jsonlite::toJSON(list(values=rnorm(10),
+                                                      options = list(type = "bar")))),
+             sapply(1:5,
+                    function(x) jsonlite::toJSON(list(values=rnorm(10),
+                                                      options = list(type = "line")))))
+
+rhandsontable(DF, rowHeaders = NULL, width = 550, height = 300) %>%
+  hot_col("chart", renderer = htmlwidgets::JS("renderSparkline"))
+```
+
+### Custom Renderer
+
+It's also possible to define a custom column renderer function.  For example, it may be desirable to include html in a cell.  The example below mimics [Custom renderers](http://docs.handsontable.com/0.16.1/demo-custom-renderers.html).
+
+```{r fig.height = 5, fig.width = 8}
+DF = data.frame(
+  title = c(
+    "<a href='http://www.amazon.com/Professional-JavaScript-Developers-Nicholas-Zakas/dp/1118026691'>Professional JavaScript for Web Developers</a>",
+    "<a href='http://shop.oreilly.com/product/9780596517748.do'>JavaScript: The Good Parts</a>",
+    "<a href='http://shop.oreilly.com/product/9780596805531.do'>JavaScript: The Definitive Guide</a>"
+  ),
+  desc = c(
+    "This <a href='http://bit.ly/sM1bDf'>book</a> provides a developer-level introduction along with more advanced and useful features of <b>JavaScript</b>.",
+    "This book provides a developer-level introduction along with <b>more advanced</b> and useful features of JavaScript.",
+    "<em>JavaScript: The Definitive Guide</em> provides a thorough description of the core <b>JavaScript</b> language and both the legacy and standard DOMs implemented in web browsers."
+  ),
+  comments = c(
+    "I would rate it &#x2605;&#x2605;&#x2605;&#x2605;&#x2606;",
+    "This is the book about JavaScript",
+    "I've never actually read it, but the <a href='http://shop.oreilly.com/product/9780596805531.do'>comments</a> are highly <strong>positive</strong>."
+  ), 
+  cover = c(
+    "http://ecx.images-amazon.com/images/I/51bRhyVTVGL._SL50_.jpg",
+    "http://ecx.images-amazon.com/images/I/51gdVAEfPUL._SL50_.jpg",
+    "http://ecx.images-amazon.com/images/I/51VFNL4T7kL._SL50_.jpg"
+ ),
+ stringsAsFactors = FALSE
+)
+
+rhandsontable(DF, allowedTags = "<em><b><strong><a><big>", 
+              width = 800, height = 450, rowHeaders = FALSE) %>%
+  hot_cols(colWidths = c(200, 200, 200, 80)) %>%
+  hot_col(1:2, renderer = "html") %>%
+  hot_col(1:3, renderer = htmlwidgets::JS("safeHtmlRenderer")) %>%
+  hot_col(4, renderer = "
+    function(instance, td, row, col, prop, value, cellProperties) {
+      var escaped = Handsontable.helper.stringify(value),
+        img;
+  
+      if (escaped.indexOf('http') === 0) {
+        img = document.createElement('IMG');
+        img.src = value;
+  
+        Handsontable.Dom.addEvent(img, 'mousedown', function (e){
+          e.preventDefault(); // prevent selection quirk
+        });
+  
+        Handsontable.Dom.empty(td);
+        td.appendChild(img);
+      }
+      else {
+        // render as text
+        Handsontable.renderers.TextRenderer.apply(this, arguments);
+      }
+  
+      return td;
+    }")
+```
+
+For `shiny` apps, use `renderer = htmlwidgets::JS("safeHtmlRenderer")` to display columns with html data.  The allowed html tags default to `<em><b><strong><a><big>`, but the (hidden) `allowedTags` parameter can in `rhandsontable` can be used to customize this list.
+
+#### Custom Renderer using an R Parameter {#custom_renderer_using_r}
+
+Additional parameters passed to `rhandsontable` will be available to the JavaScript widget via the `params` property.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+col_highlight = 2
+row_highlight = c(5, 7)
+
+rhandsontable(DF, col_highlight = col_highlight, 
+              row_highlight = row_highlight,
+              width = 550, height = 300) %>%
+  hot_cols(renderer = "
+    function(instance, td, row, col, prop, value, cellProperties) {
+      Handsontable.TextCell.renderer.apply(this, arguments);
+      
+      tbl = this.HTMLWidgets.widgets[0]
+
+      hcols = tbl.params.col_highlight
+      hcols = hcols instanceof Array ? hcols : [hcols] 
+      hrows = tbl.params.row_highlight
+      hrows = hrows instanceof Array ? hrows : [hrows] 
+
+      if (hcols.includes(col) && hrows.includes(row)) {
+        td.style.background = 'red';
+      }
+      else if (hcols.includes(col)) {
+        td.style.background = 'lightgreen';
+      }
+      else if (hrows.includes(row)) {
+        td.style.background = 'pink';
+      }
+      
+      return td;
+  }")
+```
+
+When using this approach in a shiny app or in a document with more than one widget, the widget search logic will need to be more robust.
+
+```
+HTMLWidgets.widgets.filter(function(widget) {
+  // this should match the table id specified in the shiny app
+  return widget.name === "hot"
+})[0];
+```
+
+## Right-Click Menu
+
+Right-clicking in a cell will enable a context menu that includes customizable table actions via the `hot_context_menu` function.  For shiny apps, formatting and comment updates made via the context menu are not currently retained.
+
+To disable the context menu, set `contextMenu = FALSE` in `hot_table` (or `rhandsontable`).
+
+### Add / Remove Rows & Columns
+
+By default a user can add or remove table rows and columns, but this functionality can be disabled.  Note that Handsontable does not allow column be added or deleted to the table if column types are defined (i.e. `useTypes == TRUE` in `rhandsontable`).
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE)
+```
+
+### Customizing
+
+The `customOpts` parameter of `hot_context_menu` can be used to add custom functionality to the context menu.  Below are a couple examples.
+
+#### Export to CSV
+
+This example illustrates how to add an option to export the table to a csv file.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_context_menu(
+    customOpts = list(
+      csv = list(name = "Download to CSV",
+                    callback = htmlwidgets::JS(
+                      "function (key, options) {
+                         var csv = csvString(this);
+
+                         var link = document.createElement('a');
+                         link.setAttribute('href', 'data:text/plain;charset=utf-8,' +
+                           encodeURIComponent(csv));
+                         link.setAttribute('download', 'data.csv');
+
+                         document.body.appendChild(link);
+                         link.click();
+                         document.body.removeChild(link);
+                       }"))))
+```
+
+#### Search
+
+This example illustrates how to enable the search functionality in Handsontable.
+
+```{r}
+DF = data.frame(val = 1:10,
+                bool = TRUE,
+                big = LETTERS[1:10],
+                small = factor(letters[1:10]),
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, search = TRUE, width = 550, height = 300) %>%
+  hot_context_menu(
+    customOpts = list(
+      search = list(name = "Search",
+                    callback = htmlwidgets::JS(
+                      "function (key, options) {
+                         var srch = prompt('Search criteria');
+
+                         this.search.query(srch);
+                         this.render();
+                       }"))))
+```
+
+Future enhancements will look to expand export options.
+
+## Numeric Formatting
+
+Numeric columns are formatted using the [numeral.js](http://numeraljs.com/) library.
+
+```{r}
+DF = data.frame(int = 1:10, float = rnorm(10), cur = rnorm(10) * 1E5,
+                lrg = rnorm(10) * 1E8, pct = rnorm(10))
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_col("float", format = "0.0") %>%
+  hot_col("cur", format = "$0,0.00") %>%
+  hot_col("lrg", format = "0a") %>%
+  hot_col("pct", format = "0%")
+```
+
+### Specify Locale
+
+The `language` parameter for `hot_col` can be used to change the locale.  See the [numeral.js](http://numeraljs.com/) library for language options.
+
+```{r}
+DF = data.frame(dollar = rnorm(10), euro = rnorm(10), yen = rnorm(10))
+
+rhandsontable(DF * 1000, width = 550, height = 300) %>%
+  hot_col("dollar", format = "$0,000.00", language = "en-US") %>%
+  hot_col("euro", format = "0,000.00 $", language = "de-DE") %>%
+  hot_col("yen", format = "$0,000.00", language = "ja-JP")
+```
+
+## Read Only
+
+The whole table and individual columns can to set to `readOnly` to prevent the user from making changes.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, readOnly = TRUE, width = 550, height = 300) %>%
+  hot_col("val", readOnly = FALSE)
+```
+
+## Sorting
+
+Column sorting can be enabled; sorting only impacts the widget and will not reorder the original data set.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_cols(columnSorting = TRUE)
+```
+
+## Highlight Rows & Columns
+
+With larger tables it my be desirable to highlight the row and column for a selected cell.  
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+# click on a cell to see the highlighting
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_table(highlightCol = TRUE, highlightRow = TRUE)
+```
+
+See [Custom Renderer using an R Parameter](#custom_renderer_using_r) for a static highlighting example.
+
+## Sizing
+
+Column and row dimensions can be customized.  For larger data sets, (multiple) top rows and left columns can be frozen.
+
+```{r fig.height = 6, fig.width = 6}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 600, height = 600) %>%
+  hot_cols(colWidths = 100) %>%
+  hot_rows(rowHeights = 50)
+```
+
+### Row Header Width
+
+The width of the row header column can be customized using `rowHeaderWidth`.
+
+```{r fig.height = 6, fig.width = 6}
+rhandsontable(mtcars, rowHeaderWidth = 200)
+```
+
+### Streching
+
+The table can be streched to the full width by using `stretchH`.
+
+```{r fig.height = 6, fig.width = 6}
+MAT = matrix(rnorm(30), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:3]))
+
+rhandsontable(MAT, width = 600, height = 300, stretchH = "all")
+```
+
+## Fixed Rows / Columns
+
+For larger data sets, (multiple) top rows and left columns can be frozen.
+
+```{r}
+MAT = matrix(rnorm(26 * 26), nrow = 26, dimnames = list(LETTERS, letters))
+
+# scroll through the table to see the fixed row and column
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_cols(fixedColumnsLeft = 1) %>%
+  hot_rows(fixedRowsTop = 1)
+```
+
+## Cell Comments
+
+Comments (hover) can also be added to individual cells and will appear as red flags in the upper right of the cell. 
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_cell(1, 1, "Test comment")
+```
+
+Additionally, comments can be added via `data.frame` or `matrix`.
+
+```{r}
+MAT_comments = matrix(ncol = ncol(DF), nrow = nrow(DF))
+MAT_comments[1, 1] = "Test comment"
+MAT_comments[2, 2] = "Another test comment"
+
+rhandsontable(DF, comments = MAT_comments, width = 550, height = 300)
+```
+
+Finally, comments can also be added via the right-click context menu, but these updates will not currently be retained by shiny.
+
+## Borders
+
+Custom borders can be drawn around cells to highlight specific items.  Borders can also be added via the right-click context menu, but these updates will not currently be retained by shiny.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_table(customBorders = list(list(
+    range = list(from = list(row = 1, col = 1),
+                 to = list(row = 2, col = 2)),
+    top = list(width = 2, color = "red"),
+    left = list(width = 2, color = "red"),
+    bottom = list(width = 2, color = "red"),
+    right = list(width = 2, color = "red"))))
+```
+
+## Validation
+
+### Numeric Columns
+
+Pre-defined validation can be added for numeric columns in two ways:
+
+* specify a min and max and any values within the range to exclude
+* similar to a `dropdown` column, specify allowed values
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_validate_numeric(col = 1, min = -50, max = 50, exclude = 40)
+
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_validate_numeric(col = 1, choices = c(10, 20, 40))
+```
+
+### Character Columns
+
+For character columns, a vector of allowed options can be specified.  A more user-friendly approach may be to use a `dropdown` column with `strict = TRUE`.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_validate_character(col = "big", choices = LETTERS[1:10])
+```
+
+### Custom
+
+It is also possible to create a custom validation function in JavaScript.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+# try to update any cell to 0
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_cols(validator = "
+           function (value, callback) {
+            setTimeout(function(){
+              callback(value != 0);
+            }, 1000)
+           }",
+           allowInvalid = FALSE)
+```
+
+## Conditional Formatting
+
+Conditional formatting can also be specified via custom JavaScript function.  Future enhancements will look to simplify this interface.
+
+```{r, fig.width = 8}
+MAT = matrix(runif(100, -1, 1), nrow = 10,
+             dimnames = list(LETTERS[1:10], LETTERS[1:10]))
+diag(MAT) = 1
+MAT[upper.tri(MAT)] = MAT[lower.tri(MAT)]
+rhandsontable(MAT, readOnly = TRUE, width = 750, height = 300) %>%
+  hot_cols(renderer = "
+           function (instance, td, row, col, prop, value, cellProperties) {
+             Handsontable.renderers.TextRenderer.apply(this, arguments);
+             if (row == col) {
+              td.style.background = 'lightgrey';
+             } else if (col > row) {
+              td.style.background = 'grey';
+              td.style.color = 'grey';
+             } else if (value < -0.75) {
+              td.style.background = 'pink';
+             } else if (value > 0.75) {
+              td.style.background = 'lightgreen';
+             }
+           }")
+```
+
+See [Custom Renderer using an R Parameter](#custom_renderer_using_r) for anotehr example.
+
+## Heatmap
+
+The [chroma.js](http://old.driven-by-data.net/about/chromajs/) library can be used to turn the table into a heatmap.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_heatmap()
+```
+
+## Big Data
+
+```{r}
+MAT = matrix(rnorm(10000 * 100), nrow = 100, dimnames= list(1:100, 1:10000))
+
+rhandsontable(MAT, width = 550, height = 550)
+```
+
+## Shiny
+
+**Important note on shiny use:** The `htmlwidgets` package creates widgets as shiny output bindings.  The `rhandsontable` package also attempts to expose the table as a *pseudo* shiny input binding using handsontable change events (see [here](https://github.com/jrowen/rhandsontable/blob/master/inst/htmlwidgets/rhandsontable.js) for the supported events).  **This means the table (e.g. `hot`) can be accessed in shiny using either `input$hot` or `output$hot`, but these values may not be in- [...]
+
+Since the widget is not currently able to use the standard shiny input binding functionality, you will need to explicitly call the `hot_to_r` function to convert the handsontable data to an R object.
+
+Two additional inputs are also enabled, `input$hot_select` and `input$hot_comment`, which will fire when a cell selection or a comment changes, respectively (if you would like to see more options, please post an issue or create a PR).
+
+This functionality is still evolving, so please don't hesitate to share suggestions and PRs.
+
+The data grid will be editable by default and can be used as input to a `shiny` app.  A few `shiny` and `shinydashboard` example links are listed below.  Note that the shinyapps.io links may not work if the has hit the monthly usage limit.
+
+* [Output only](https://jrowen.shinyapps.io/rhandsontable_output)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_output")
+```
+* [Date file editor](https://jrowen.shinyapps.io/rhandsontable_datafile)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_datafile")
+```
+* [Calculation input](https://jrowen.shinyapps.io/rhandsontable_portfolio)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_portfolio")
+```
+* [Table callback linked to chart](https://jrowen.shinyapps.io/rhandsontable_corr)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_corr")
+```
+* [Multiple input tables](https://jrowen.shinyapps.io/rhandsontable_frontier)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_frontier")
+```
+* [A shinydashboard app](https://jrowen.shinyapps.io/rhandsontable_dash)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir="inst/examples/rhandsontable_dash")
+```
+
+### Bookmarks
+
+Version 0.14 of `shiny` includes new bookmarking functionality.  This willl work for `rhandsontable` with some special handling.  See [this issue](https://github.com/rstudio/shiny/issues/1378) for more details.
+
+## Suggestions & Contributions
+
+Please file a issue if you experience any problems with the widget or have feature requests.  Pull requests are also welcome.
diff --git a/inst/doc/intro_rhandsontable.html b/inst/doc/intro_rhandsontable.html
new file mode 100644
index 0000000..a987a19
--- /dev/null
+++ b/inst/doc/intro_rhandsontable.html
@@ -0,0 +1,650 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+<meta name="viewport" content="width=device-width, initial-scale=1">
+
+<meta name="author" content="Jonathan Owen" />
+
+<meta name="date" content="2016-11-03" />
+
+<title>rhandsontable Introduction</title>
+
+<script src="data:application/x-javascript;base64,KGZ1bmN0aW9uKCkgewogIC8vIElmIHdpbmRvdy5IVE1MV2lkZ2V0cyBpcyBhbHJlYWR5IGRlZmluZWQsIHRoZW4gdXNlIGl0OyBvdGhlcndpc2UgY3JlYXRlIGEKICAvLyBuZXcgb2JqZWN0LiBUaGlzIGFsbG93cyBwcmVjZWRpbmcgY29kZSB0byBzZXQgb3B0aW9ucyB0aGF0IGFmZmVjdCB0aGUKICAvLyBpbml0aWFsaXphdGlvbiBwcm9jZXNzICh0aG91Z2ggbm9uZSBjdXJyZW50bHkgZXhpc3QpLgogIHdpbmRvdy5IVE1MV2lkZ2V0cyA9IHdpbmRvdy5IVE1MV2lkZ2V0cyB8fCB7fTsKCiAgLy8gU2VlIGlmIHdlJ3JlIHJ1bm5pbmcgaW4gYSB2aWV3ZXIgcGFuZS4gSWYgbm90LCB3ZS [...]
+<link href="data:text/css;charset=utf-8,%40charset%20%22UTF%2D8%22%3B%2Ehandsontable%7Bposition%3Arelative%7D%2Ehandsontable%20%2Ehide%7Bdisplay%3Anone%7D%2Ehandsontable%20%2Erelative%7Bposition%3Arelative%7D%2Ehandsontable%2EhtAutoSize%7Bvisibility%3Ahidden%3Bleft%3A%2D99000px%3Bposition%3Aabsolute%3Btop%3A%2D99000px%7D%2Ehandsontable%20%2EwtHider%7Bwidth%3A0%7D%2Ehandsontable%20%2EwtSpreader%7Bposition%3Arelative%3Bwidth%3A0%3Bheight%3Aauto%7D%2Ehandsontable%20table%2C%2Ehandsontable%2 [...]
+<script src="data:application/x-javascript;base64,LyohCihUaGUgTUlUIExpY2Vuc2UpCgpDb3B5cmlnaHQgKGMpIDIwMTItMjAxNCBNYXJjaW4gV2FycGVjaG93c2tpCkNvcHlyaWdodCAoYykgMjAxNSBIYW5kc29uY29kZSBzcC4geiBvLm8uIDxoZWxsb0BoYW5kc29uY29kZS5uZXQ+CgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcKYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlCidTb2Z0d2FyZScpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdW [...]
+<script src="data:application/x-javascript;base64,LyohCiAqIG51bWJyby5qcyBsYW5ndWFnZSBjb25maWd1cmF0aW9uCiAqIGxhbmd1YWdlIDogQ3plY2gKICogbG9jYWxlOiBDemVjaCBSZXB1YmxpYwogKiBhdXRob3IgOiBBbmF0b2xpIFBhcGlyb3Zza2kgOiBodHRwczovL2dpdGh1Yi5jb20vYXBhcGlyb3Zza2kKICovCihmdW5jdGlvbiAoKSB7CiAgICAndXNlIHN0cmljdCc7CgogICAgdmFyIGxhbmd1YWdlID0gewogICAgICAgIGxhbmdMb2NhbGVDb2RlOiAnY3MtQ1onLAogICAgICAgIGN1bHR1cmVDb2RlOiAnY3MtQ1onLAogICAgICAgIGRlbGltaXRlcnM6IHsKICAgICAgICAgICAgdGhvdXNhbmRzOiAnICcsCiAgICAgICAgIC [...]
+<script src="data:application/x-javascript;base64,LyoKY2hyb21hLmpzIC0gSmF2YVNjcmlwdCBsaWJyYXJ5IGZvciBjb2xvciBjb252ZXJzaW9ucwoKQ29weXJpZ2h0IChjKSAyMDExLTIwMTUsIEdyZWdvciBBaXNjaApBbGwgcmlnaHRzIHJlc2VydmVkLgoKUmVkaXN0cmlidXRpb24gYW5kIHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBmb3Jtcywgd2l0aCBvciB3aXRob3V0Cm1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUgbWV0OgoKMS4gUmVkaXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3QgcmV0YWluIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aW [...]
+<script src="data:application/x-javascript;base64,LyohIGpRdWVyeSB2Mi4yLjEgfCAoYykgalF1ZXJ5IEZvdW5kYXRpb24gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8KIWZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBtb2R1bGUmJiJvYmplY3QiPT10eXBlb2YgbW9kdWxlLmV4cG9ydHM/bW9kdWxlLmV4cG9ydHM9YS5kb2N1bWVudD9iKGEsITApOmZ1bmN0aW9uKGEpe2lmKCFhLmRvY3VtZW50KXRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpO3JldHVybiBiKGEpfTpiKGEpfSgidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6dGhpcyxmdW5jdGlvbihhLGIpe3 [...]
+<script src="data:application/x-javascript;base64,LyoganF1ZXJ5LnNwYXJrbGluZSAyLjEuMyAtIGh0dHA6Ly9vbW5pcG90ZW50Lm5ldC9qcXVlcnkuc3BhcmtsaW5lLyAKIExpY2Vuc2VkIHVuZGVyIHRoZSBOZXcgQlNEIExpY2Vuc2UgLSBzZWUgYWJvdmUgc2l0ZSBmb3IgZGV0YWlscyAqLwohZnVuY3Rpb24oYSxiLGMpeyFmdW5jdGlvbihhKXsiZnVuY3Rpb24iPT10eXBlb2YgZGVmaW5lJiZkZWZpbmUuYW1kP2RlZmluZSgianF1ZXJ5LnNwYXJrbGluZSIsWyJqcXVlcnkiXSxhKTpqUXVlcnkmJiFqUXVlcnkuZm4uc3BhcmtsaW5lJiZhKGpRdWVyeSl9KGZ1bmN0aW9uKGQpeyJ1c2Ugc3RyaWN0Ijt2YXIgZSxmLGcsaCxpLGosayxsLG [...]
+<link href="data:text/css;charset=utf-8,%2Ehandsontable%20%2EcurrentRow%20%7B%0Abackground%2Dcolor%3A%20%23E7E8EF%3B%0A%7D%0A%2Ehandsontable%20%2EcurrentCol%20%7B%0Abackground%2Dcolor%3A%20%23F9F9FB%3B%0A%7D%0A%2Ehandsontable%20%7B%0Aoverflow%3A%20auto%3B%0A%7D%0A%0A%2Ejqstooltip%7B%0Awidth%3A%20auto%20%21important%3B%0Aheight%3A%20auto%20%21important%3B%0A%7D%0A%0A%2Edatepicker%20%7B%0Az%2Dindex%3A%201000%20%21important%3B%0A%7D%0A%2Ehandsontable%20table%20thead%20th%20%7B%0Awhite%2Dspa [...]
+<script src="data:application/x-javascript;base64,SFRNTFdpZGdldHMud2lkZ2V0KHsKCiAgbmFtZTogJ3JoYW5kc29udGFibGUnLAoKICB0eXBlOiAnb3V0cHV0JywKCiAgcGFyYW1zOiBudWxsLAoKICBpbml0aWFsaXplOiBmdW5jdGlvbihlbCwgd2lkdGgsIGhlaWdodCkgewoKICAgIHJldHVybiB7CgogICAgfTsKCiAgfSwKCiAgcmVuZGVyVmFsdWU6IGZ1bmN0aW9uKGVsLCB4LCBpbnN0YW5jZSkgewoKICAgIC8vIGNvbnZlcnQganNvbiB0byBhcnJheQogICAgaWYgKHguZGF0YS5sZW5ndGggPiAwICYmIHguZGF0YVswXS5jb25zdHJ1Y3RvciA9PT0gQXJyYXkpIHsKICAgICAgeC5kYXRhID0geC5kYXRhOwogICAgfSBlbHNlIHsKIC [...]
+
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+div.sourceCode { overflow-x: auto; }
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
+  margin: 0; padding: 0; vertical-align: baseline; border: none; }
+table.sourceCode { width: 100%; line-height: 100%; }
+td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
+td.sourceCode { padding-left: 5px; }
+code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code > span.dt { color: #902000; } /* DataType */
+code > span.dv { color: #40a070; } /* DecVal */
+code > span.bn { color: #40a070; } /* BaseN */
+code > span.fl { color: #40a070; } /* Float */
+code > span.ch { color: #4070a0; } /* Char */
+code > span.st { color: #4070a0; } /* String */
+code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code > span.ot { color: #007020; } /* Other */
+code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code > span.fu { color: #06287e; } /* Function */
+code > span.er { color: #ff0000; font-weight: bold; } /* Error */
+code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+code > span.cn { color: #880000; } /* Constant */
+code > span.sc { color: #4070a0; } /* SpecialChar */
+code > span.vs { color: #4070a0; } /* VerbatimString */
+code > span.ss { color: #bb6688; } /* SpecialString */
+code > span.im { } /* Import */
+code > span.va { color: #19177c; } /* Variable */
+code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code > span.op { color: #666666; } /* Operator */
+code > span.bu { } /* BuiltIn */
+code > span.ex { } /* Extension */
+code > span.pp { color: #bc7a00; } /* Preprocessor */
+code > span.at { color: #7d9029; } /* Attribute */
+code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+</style>
+
+
+
+<link href="data:text/css;charset=utf-8,body%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0Amargin%3A%201em%20auto%3B%0Amax%2Dwidth%3A%20700px%3B%0Aoverflow%3A%20visible%3B%0Apadding%2Dleft%3A%202em%3B%0Apadding%2Dright%3A%202em%3B%0Afont%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E35%3B%0A%7D%0A%23header%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%23TOC%20%7B%0Aclear%3A%20bot [...]
+
+</head>
+
+<body>
+
+
+
+
+<h1 class="title toc-ignore">rhandsontable Introduction</h1>
+<h4 class="author"><em>Jonathan Owen</em></h4>
+<h4 class="date"><em>2016-11-03</em></h4>
+
+
+
+<div id="introduction" class="section level2">
+<h2>Introduction</h2>
+<p>rhandsontable is a htmlwidget based on the <a href="https://www.handsontable.com">handsontable.js</a> library.</p>
+<blockquote>
+<p>Handsontable is a data grid component with an Excel-like appearance. Built in JavaScript, it integrates with any data source with peak efficiency. It comes with powerful features like data validation, sorting, grouping, data binding, formula support or column ordering. (<a href="https://www.handsontable.com">via</a>)</p>
+</blockquote>
+</div>
+<div id="column-types" class="section level2">
+<h2>Column Types</h2>
+<p>The table includes support for numeric, logical, character and Date types. Logical values will appear as check boxes, and the <a href="https://github.com/dbushell/Pikaday">pikaday.js</a> library is used to specify Date values.</p>
+<p>rhandsontable attempts to map R classes to an appropriate handsontable type. Factors will be mapped to <code>dropdown</code>, with the choices specified by <code>level</code> and <code>allowInvalid</code> set to <code>FALSE</code>. To allow new levels, set <code>allowInvalid</code> to <code>TRUE</code> (using <code>hot_col</code>; it may also be desirable to set <code>strict</code> to <code>FALSE</code>). When running in <code>shiny</code>, using <code>hot_to_r</code> will preserve cu [...]
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">integer =</span> <span class="dv">1</span>:<span class="dv">10</span>,
+                   <span class="dt">numeric =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>),
+                   <span class="dt">logical =</span> <span class="kw">rep</span>(<span class="ot">TRUE</span>, <span class="dv">10</span>), 
+                   <span class="dt">character =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                   <span class="dt">factor =</span> <span class="kw">factor</span>(letters[<span class="dv">1</span>:<span class="dv">10</span>], <span class="dt">levels =</span> letters[<span class="dv">10</span>:<span class="dv">1</span>], 
+                                   <span class="dt">ordered =</span> <span class="ot">TRUE</span>),
+                   <span class="dt">factor_allow =</span> <span class="kw">factor</span>(letters[<span class="dv">1</span>:<span class="dv">10</span>], <span class="dt">levels =</span> letters[<span class="dv">10</span>:<span class="dv">1</span>], 
+                                         <span class="dt">ordered =</span> <span class="ot">TRUE</span>),
+                   <span class="dt">date =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                   <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">600</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"factor_allow"</span>, <span class="dt">allowInvalid =</span> <span class="ot">TRUE</span>)</code></pre></div>
+<div id="htmlwidget-6546" style="width:600px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-6546">{"x":{"data":[{"integer":1,"numeric":0.7479,"logical":true,"character":"A","factor":"a","factor_allow":"a","date":"11/03/2016"},{"integer":2,"numeric":0.0606,"logical":true,"character":"B","factor":"b","factor_allow":"b","date":"11/04/2016"},{"integer":3,"numeric":-0.1162,"logical":true,"character":"C","factor":"c","factor_allow":"c","date":"11/05/2016"},{"integer":4,"numeric":-0.5721,"logical":true,"character":"D","factor":"d"," [...]
+<p>To improve readability, <code>NA</code> values will be displayed as blank cells. This requires converting columns containing <code>NA</code> to characters, and in the case of factors and Dates, may not display the data in the desired format. It may be beneficial to concert these type of columns to character before passing to <code>rhandsontable</code>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF_na =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">integer =</span> <span class="kw">c</span>(<span class="ot">NA</span>, <span class="dv">2</span>:<span class="dv">10</span>), 
+                   <span class="dt">logical =</span> <span class="kw">c</span>(<span class="ot">NA</span>, <span class="kw">rep</span>(<span class="ot">TRUE</span>, <span class="dv">9</span>)), 
+                   <span class="dt">character =</span> <span class="kw">c</span>(<span class="ot">NA</span>, LETTERS[<span class="dv">1</span>:<span class="dv">9</span>]),
+                   <span class="dt">factor =</span> <span class="kw">c</span>(<span class="ot">NA</span>, <span class="kw">factor</span>(letters[<span class="dv">1</span>:<span class="dv">9</span>])),
+                   <span class="dt">date =</span> <span class="kw">c</span>(<span class="ot">NA</span>, <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, 
+                                    <span class="dt">length.out =</span> <span class="dv">9</span>)),
+                   <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+DF_na$factor_ch =<span class="st"> </span><span class="kw">as.character</span>(DF_na$factor)
+DF_na$date_ch =<span class="st"> </span><span class="kw">c</span>(<span class="ot">NA</span>, <span class="kw">as.character</span>(<span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, 
+                                       <span class="dt">length.out =</span> <span class="dv">9</span>)))
+
+<span class="kw">rhandsontable</span>(DF_na, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>)</code></pre></div>
+<div id="htmlwidget-9475" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-9475">{"x":{"data":[{"integer":"NA","logical":"NA","character":"NA","factor":"NA","date":"NA","factor_ch":"NA","date_ch":"NA"},{"integer":2,"logical":true,"character":"A","factor":1,"date":17108,"factor_ch":"1","date_ch":"2016-11-03"},{"integer":3,"logical":true,"character":"B","factor":2,"date":17109,"factor_ch":"2","date_ch":"2016-11-04"},{"integer":4,"logical":true,"character":"C","factor":3,"date":17110,"factor_ch":"3","date_ch":"2 [...]
+<div id="dropdown-autocomplete" class="section level3">
+<h3>Dropdown / Autocomplete</h3>
+<p>To control character column values, the column type can be specified as <code>dropdown</code> or <code>autocomplete</code>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="co"># try updating big to a value not in the dropdown</span>
+<span class="kw">rhandsontable</span>(DF, <span class="dt">rowHeaders =</span> <span class="ot">NULL</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="dt">col =</span> <span class="st">"big"</span>, <span class="dt">type =</span> <span class="st">"dropdown"</span>, <span class="dt">source =</span> LETTERS) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="dt">col =</span> <span class="st">"small"</span>, <span class="dt">type =</span> <span class="st">"autocomplete"</span>, <span class="dt">source =</span> letters,
+          <span class="dt">strict =</span> <span class="ot">FALSE</span>)</code></pre></div>
+<div id="htmlwidget-8702" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-8702">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+</div>
+<div id="password" class="section level3">
+<h3>Password</h3>
+<p>A column can also be specified as a <code>password</code> type.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"small"</span>, <span class="st">"password"</span>)</code></pre></div>
+<div id="htmlwidget-4640" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-4640">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+</div>
+<div id="sparkline" class="section level3">
+<h3>Sparkline</h3>
+<p>New in version 0.2, <a href="http://omnipotent.net/jquery.sparkline/">sparkline.js</a> charts can be added to the table. Thanks to the sparkline package and Ramnath Vaidyanathan for inspiration.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+DF$chart =<span class="st"> </span><span class="kw">c</span>(<span class="kw">sapply</span>(<span class="dv">1</span>:<span class="dv">5</span>,
+                    function(x) jsonlite::<span class="kw">toJSON</span>(<span class="kw">list</span>(<span class="dt">values=</span><span class="kw">rnorm</span>(<span class="dv">10</span>),
+                                                      <span class="dt">options =</span> <span class="kw">list</span>(<span class="dt">type =</span> <span class="st">"bar"</span>)))),
+             <span class="kw">sapply</span>(<span class="dv">1</span>:<span class="dv">5</span>,
+                    function(x) jsonlite::<span class="kw">toJSON</span>(<span class="kw">list</span>(<span class="dt">values=</span><span class="kw">rnorm</span>(<span class="dv">10</span>),
+                                                      <span class="dt">options =</span> <span class="kw">list</span>(<span class="dt">type =</span> <span class="st">"line"</span>)))))
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">rowHeaders =</span> <span class="ot">NULL</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"chart"</span>, <span class="dt">renderer =</span> htmlwidgets::<span class="kw">JS</span>(<span class="st">"renderSparkline"</span>))</code></pre></div>
+<div id="htmlwidget-8249" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-8249">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016","chart":"{\"values\":[1.0426,-0.1826,-1.9209,0.3206,0.1651,0.8153,-1.316,0.2677,-0.6637,-0.0335],\"options\":{\"type\":[\"bar\"]}}"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016","chart":"{\"values\":[0.1011,1.3829,-0.5461,-0.3973,-0.8329,-1.2919,-0.1692,1.0456,-1.276,-0.0216],\"options\":{\"type\":[\"bar\"]}}"},{"val":3,"bool":true,"big":"C [...]
+</div>
+<div id="custom-renderer" class="section level3">
+<h3>Custom Renderer</h3>
+<p>It’s also possible to define a custom column renderer function. For example, it may be desirable to include html in a cell. The example below mimics <a href="http://docs.handsontable.com/0.16.1/demo-custom-renderers.html">Custom renderers</a>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(
+  <span class="dt">title =</span> <span class="kw">c</span>(
+    <span class="st">"<a href='http://www.amazon.com/Professional-JavaScript-Developers-Nicholas-Zakas/dp/1118026691'>Professional JavaScript for Web Developers</a>"</span>,
+    <span class="st">"<a href='http://shop.oreilly.com/product/9780596517748.do'>JavaScript: The Good Parts</a>"</span>,
+    <span class="st">"<a href='http://shop.oreilly.com/product/9780596805531.do'>JavaScript: The Definitive Guide</a>"</span>
+  ),
+  <span class="dt">desc =</span> <span class="kw">c</span>(
+    <span class="st">"This <a href='http://bit.ly/sM1bDf'>book</a> provides a developer-level introduction along with more advanced and useful features of <b>JavaScript</b>."</span>,
+    <span class="st">"This book provides a developer-level introduction along with <b>more advanced</b> and useful features of JavaScript."</span>,
+    <span class="st">"<em>JavaScript: The Definitive Guide</em> provides a thorough description of the core <b>JavaScript</b> language and both the legacy and standard DOMs implemented in web browsers."</span>
+  ),
+  <span class="dt">comments =</span> <span class="kw">c</span>(
+    <span class="st">"I would rate it &#x2605;&#x2605;&#x2605;&#x2605;&#x2606;"</span>,
+    <span class="st">"This is the book about JavaScript"</span>,
+    <span class="st">"I've never actually read it, but the <a href='http://shop.oreilly.com/product/9780596805531.do'>comments</a> are highly <strong>positive</strong>."</span>
+  ), 
+  <span class="dt">cover =</span> <span class="kw">c</span>(
+    <span class="st">"http://ecx.images-amazon.com/images/I/51bRhyVTVGL._SL50_.jpg"</span>,
+    <span class="st">"http://ecx.images-amazon.com/images/I/51gdVAEfPUL._SL50_.jpg"</span>,
+    <span class="st">"http://ecx.images-amazon.com/images/I/51VFNL4T7kL._SL50_.jpg"</span>
+ ),
+ <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>
+)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">allowedTags =</span> <span class="st">"<em><b><strong><a><big>"</span>, 
+              <span class="dt">width =</span> <span class="dv">800</span>, <span class="dt">height =</span> <span class="dv">450</span>, <span class="dt">rowHeaders =</span> <span class="ot">FALSE</span>) %>%
+<span class="st">  </span><span class="kw">hot_cols</span>(<span class="dt">colWidths =</span> <span class="kw">c</span>(<span class="dv">200</span>, <span class="dv">200</span>, <span class="dv">200</span>, <span class="dv">80</span>)) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="dv">1</span>:<span class="dv">2</span>, <span class="dt">renderer =</span> <span class="st">"html"</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="dv">1</span>:<span class="dv">3</span>, <span class="dt">renderer =</span> htmlwidgets::<span class="kw">JS</span>(<span class="st">"safeHtmlRenderer"</span>)) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="dv">4</span>, <span class="dt">renderer =</span> <span class="st">"</span>
+<span class="st">    function(instance, td, row, col, prop, value, cellProperties) {</span>
+<span class="st">      var escaped = Handsontable.helper.stringify(value),</span>
+<span class="st">        img;</span>
+<span class="st">  </span>
+<span class="st">      if (escaped.indexOf('http') === 0) {</span>
+<span class="st">        img = document.createElement('IMG');</span>
+<span class="st">        img.src = value;</span>
+<span class="st">  </span>
+<span class="st">        Handsontable.Dom.addEvent(img, 'mousedown', function (e){</span>
+<span class="st">          e.preventDefault(); // prevent selection quirk</span>
+<span class="st">        });</span>
+<span class="st">  </span>
+<span class="st">        Handsontable.Dom.empty(td);</span>
+<span class="st">        td.appendChild(img);</span>
+<span class="st">      }</span>
+<span class="st">      else {</span>
+<span class="st">        // render as text</span>
+<span class="st">        Handsontable.renderers.TextRenderer.apply(this, arguments);</span>
+<span class="st">      }</span>
+<span class="st">  </span>
+<span class="st">      return td;</span>
+<span class="st">    }"</span>)</code></pre></div>
+<div id="htmlwidget-1331" style="width:800px;height:450px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-1331">{"x":{"data":[{"title":"<a href='http://www.amazon.com/Professional-JavaScript-Developers-Nicholas-Zakas/dp/1118026691'>Professional JavaScript for Web Developers\u003c/a>","desc":"This <a href='http://bit.ly/sM1bDf'>book\u003c/a> provides a developer-level introduction along with more advanced and useful features of <b>JavaScript\u003c/b>.","comments":"I would rate it &#x2605;&#x2605;&#x2605;&#x2605;&#x2606;","cover":"http://ecx [...]
+<p>For <code>shiny</code> apps, use <code>renderer = htmlwidgets::JS("safeHtmlRenderer")</code> to display columns with html data. The allowed html tags default to <code><em><b><strong><a><big></code>, but the (hidden) <code>allowedTags</code> parameter can in <code>rhandsontable</code> can be used to customize this list.</p>
+<div id="custom_renderer_using_r" class="section level4">
+<h4>Custom Renderer using an R Parameter</h4>
+<p>Additional parameters passed to <code>rhandsontable</code> will be available to the JavaScript widget via the <code>params</code> property.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+col_highlight =<span class="st"> </span><span class="dv">2</span>
+row_highlight =<span class="st"> </span><span class="kw">c</span>(<span class="dv">5</span>, <span class="dv">7</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">col_highlight =</span> col_highlight, 
+              <span class="dt">row_highlight =</span> row_highlight,
+              <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_cols</span>(<span class="dt">renderer =</span> <span class="st">"</span>
+<span class="st">    function(instance, td, row, col, prop, value, cellProperties) {</span>
+<span class="st">      Handsontable.TextCell.renderer.apply(this, arguments);</span>
+<span class="st">      </span>
+<span class="st">      tbl = this.HTMLWidgets.widgets[0]</span>
+
+<span class="st">      hcols = tbl.params.col_highlight</span>
+<span class="st">      hcols = hcols instanceof Array ? hcols : [hcols] </span>
+<span class="st">      hrows = tbl.params.row_highlight</span>
+<span class="st">      hrows = hrows instanceof Array ? hrows : [hrows] </span>
+
+<span class="st">      if (hcols.includes(col) && hrows.includes(row)) {</span>
+<span class="st">        td.style.background = 'red';</span>
+<span class="st">      }</span>
+<span class="st">      else if (hcols.includes(col)) {</span>
+<span class="st">        td.style.background = 'lightgreen';</span>
+<span class="st">      }</span>
+<span class="st">      else if (hrows.includes(row)) {</span>
+<span class="st">        td.style.background = 'pink';</span>
+<span class="st">      }</span>
+<span class="st">      </span>
+<span class="st">      return td;</span>
+<span class="st">  }"</span>)</code></pre></div>
+<div id="htmlwidget-3170" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-3170">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+<p>When using this approach in a shiny app or in a document with more than one widget, the widget search logic will need to be more robust.</p>
+<pre><code>HTMLWidgets.widgets.filter(function(widget) {
+  // this should match the table id specified in the shiny app
+  return widget.name === "hot"
+})[0];</code></pre>
+</div>
+</div>
+</div>
+<div id="right-click-menu" class="section level2">
+<h2>Right-Click Menu</h2>
+<p>Right-clicking in a cell will enable a context menu that includes customizable table actions via the <code>hot_context_menu</code> function. For shiny apps, formatting and comment updates made via the context menu are not currently retained.</p>
+<p>To disable the context menu, set <code>contextMenu = FALSE</code> in <code>hot_table</code> (or <code>rhandsontable</code>).</p>
+<div id="add-remove-rows-columns" class="section level3">
+<h3>Add / Remove Rows & Columns</h3>
+<p>By default a user can add or remove table rows and columns, but this functionality can be disabled. Note that Handsontable does not allow column be added or deleted to the table if column types are defined (i.e. <code>useTypes == TRUE</code> in <code>rhandsontable</code>).</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_context_menu</span>(<span class="dt">allowRowEdit =</span> <span class="ot">FALSE</span>, <span class="dt">allowColEdit =</span> <span class="ot">FALSE</span>)</code></pre></div>
+<div id="htmlwidget-2981" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-2981">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+</div>
+<div id="customizing" class="section level3">
+<h3>Customizing</h3>
+<p>The <code>customOpts</code> parameter of <code>hot_context_menu</code> can be used to add custom functionality to the context menu. Below are a couple examples.</p>
+<div id="export-to-csv" class="section level4">
+<h4>Export to CSV</h4>
+<p>This example illustrates how to add an option to export the table to a csv file.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">50</span>), <span class="dt">nrow =</span> <span class="dv">10</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                                                   letters[<span class="dv">1</span>:<span class="dv">5</span>]))
+
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_context_menu</span>(
+    <span class="dt">customOpts =</span> <span class="kw">list</span>(
+      <span class="dt">csv =</span> <span class="kw">list</span>(<span class="dt">name =</span> <span class="st">"Download to CSV"</span>,
+                    <span class="dt">callback =</span> htmlwidgets::<span class="kw">JS</span>(
+                      <span class="st">"function (key, options) {</span>
+<span class="st">                         var csv = csvString(this);</span>
+
+<span class="st">                         var link = document.createElement('a');</span>
+<span class="st">                         link.setAttribute('href', 'data:text/plain;charset=utf-8,' +</span>
+<span class="st">                           encodeURIComponent(csv));</span>
+<span class="st">                         link.setAttribute('download', 'data.csv');</span>
+
+<span class="st">                         document.body.appendChild(link);</span>
+<span class="st">                         link.click();</span>
+<span class="st">                         document.body.removeChild(link);</span>
+<span class="st">                       }"</span>))))</code></pre></div>
+<div id="htmlwidget-4518" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-4518">{"x":{"data":[[0.069,-1.5964,-0.2281,-1.3184,0.5475],[2.824,0.8386,-0.397,1.1561,0.1715],[-1.1639,0.3461,-0.5558,-0.4886,-1.4796],[-0.9424,-1.2273,0.6376,-0.3874,-0.3734],[-0.9127,0.9592,-1.9493,-1.6453,-1.2259],[1.8598,1.2581,0.4525,0.1041,1.4597],[-0.74,1.1635,1.3004,-0.3477,0.7676],[0.2181,0.8554,0.205,-0.6775,-1.676],[0.0686,-0.8363,1.0957,-0.5392,-0.8947],[-0.0388,-0.6742,0.707,-0.0855,-0.0136]],"rClass":"matrix","rColClasse [...]
+</div>
+<div id="search" class="section level4">
+<h4>Search</h4>
+<p>This example illustrates how to enable the search functionality in Handsontable.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>,
+                <span class="dt">bool =</span> <span class="ot">TRUE</span>,
+                <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> <span class="kw">factor</span>(letters[<span class="dv">1</span>:<span class="dv">10</span>]),
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">search =</span> <span class="ot">TRUE</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_context_menu</span>(
+    <span class="dt">customOpts =</span> <span class="kw">list</span>(
+      <span class="dt">search =</span> <span class="kw">list</span>(<span class="dt">name =</span> <span class="st">"Search"</span>,
+                    <span class="dt">callback =</span> htmlwidgets::<span class="kw">JS</span>(
+                      <span class="st">"function (key, options) {</span>
+<span class="st">                         var srch = prompt('Search criteria');</span>
+
+<span class="st">                         this.search.query(srch);</span>
+<span class="st">                         this.render();</span>
+<span class="st">                       }"</span>))))</code></pre></div>
+<div id="htmlwidget-9987" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-9987">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+<p>Future enhancements will look to expand export options.</p>
+</div>
+</div>
+</div>
+<div id="numeric-formatting" class="section level2">
+<h2>Numeric Formatting</h2>
+<p>Numeric columns are formatted using the <a href="http://numeraljs.com/">numeral.js</a> library.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">int =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">float =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>), <span class="dt">cur =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>) *<span class="st"> </span><span class="fl">1E5</span>,
+                <span class="dt">lrg =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>) *<span class="st"> </span><span class="fl">1E8</span>, <span class="dt">pct =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>))
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"float"</span>, <span class="dt">format =</span> <span class="st">"0.0"</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"cur"</span>, <span class="dt">format =</span> <span class="st">"$0,0.00"</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"lrg"</span>, <span class="dt">format =</span> <span class="st">"0a"</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"pct"</span>, <span class="dt">format =</span> <span class="st">"0%"</span>)</code></pre></div>
+<div id="htmlwidget-155" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-155">{"x":{"data":[{"int":1,"float":-0.3704,"cur":-24702.2534,"lrg":-80985828.7949,"pct":1.0192},{"int":2,"float":0.7847,"cur":-40883.4996,"lrg":-23299761.9653,"pct":-0.2477},{"int":3,"float":0.5166,"cur":-68063.0846,"lrg":-160373924.6329,"pct":0.3772},{"int":4,"float":0.4254,"cur":88407.2751,"lrg":-75013637.7784,"pct":-1.126},{"int":5,"float":-0.7238,"cur":-56036.1912,"lrg":78274444.0051,"pct":0.9815},{"int":6,"float":-0.0077,"cur":15 [...]
+<div id="specify-locale" class="section level3">
+<h3>Specify Locale</h3>
+<p>The <code>language</code> parameter for <code>hot_col</code> can be used to change the locale. See the <a href="http://numeraljs.com/">numeral.js</a> library for language options.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">dollar =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>), <span class="dt">euro =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>), <span class="dt">yen =</span> <span class="kw">rnorm</span>(<span class="dv">10</span>))
+
+<span class="kw">rhandsontable</span>(DF *<span class="st"> </span><span class="dv">1000</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"dollar"</span>, <span class="dt">format =</span> <span class="st">"$0,000.00"</span>, <span class="dt">language =</span> <span class="st">"en-US"</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"euro"</span>, <span class="dt">format =</span> <span class="st">"0,000.00 $"</span>, <span class="dt">language =</span> <span class="st">"de-DE"</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"yen"</span>, <span class="dt">format =</span> <span class="st">"$0,000.00"</span>, <span class="dt">language =</span> <span class="st">"ja-JP"</span>)</code></pre></div>
+<div id="htmlwidget-4363" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-4363">{"x":{"data":[{"dollar":-1076.4714,"euro":-458.3475,"yen":309.1631},{"dollar":-1366.6867,"euro":685.635,"yen":-639.9951},{"dollar":-197.8544,"euro":1157.7487,"yen":691.3339},{"dollar":203.0936,"euro":910.4645,"yen":295.2693},{"dollar":-1474.0225,"euro":-77.9102,"yen":-1040.668},{"dollar":120.1163,"euro":-396.8672,"yen":-35.578},{"dollar":767.4509,"euro":804.5724,"yen":502.8554},{"dollar":279.5081,"euro":1275.0881,"yen":469.6526}, [...]
+</div>
+</div>
+<div id="read-only" class="section level2">
+<h2>Read Only</h2>
+<p>The whole table and individual columns can to set to <code>readOnly</code> to prevent the user from making changes.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">readOnly =</span> <span class="ot">TRUE</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_col</span>(<span class="st">"val"</span>, <span class="dt">readOnly =</span> <span class="ot">FALSE</span>)</code></pre></div>
+<div id="htmlwidget-5965" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-5965">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+</div>
+<div id="sorting" class="section level2">
+<h2>Sorting</h2>
+<p>Column sorting can be enabled; sorting only impacts the widget and will not reorder the original data set.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_cols</span>(<span class="dt">columnSorting =</span> <span class="ot">TRUE</span>)</code></pre></div>
+<div id="htmlwidget-1498" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-1498">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+</div>
+<div id="highlight-rows-columns" class="section level2">
+<h2>Highlight Rows & Columns</h2>
+<p>With larger tables it my be desirable to highlight the row and column for a selected cell.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="co"># click on a cell to see the highlighting</span>
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_table</span>(<span class="dt">highlightCol =</span> <span class="ot">TRUE</span>, <span class="dt">highlightRow =</span> <span class="ot">TRUE</span>)</code></pre></div>
+<div id="htmlwidget-9685" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-9685">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+<p>See <a href="#custom_renderer_using_r">Custom Renderer using an R Parameter</a> for a static highlighting example.</p>
+</div>
+<div id="sizing" class="section level2">
+<h2>Sizing</h2>
+<p>Column and row dimensions can be customized. For larger data sets, (multiple) top rows and left columns can be frozen.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">50</span>), <span class="dt">nrow =</span> <span class="dv">10</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                                                   letters[<span class="dv">1</span>:<span class="dv">5</span>]))
+
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">width =</span> <span class="dv">600</span>, <span class="dt">height =</span> <span class="dv">600</span>) %>%
+<span class="st">  </span><span class="kw">hot_cols</span>(<span class="dt">colWidths =</span> <span class="dv">100</span>) %>%
+<span class="st">  </span><span class="kw">hot_rows</span>(<span class="dt">rowHeights =</span> <span class="dv">50</span>)</code></pre></div>
+<div id="htmlwidget-88" style="width:600px;height:600px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-88">{"x":{"data":[[-1.9008,-0.0398,-0.1523,1.4705,0.2153],[-0.0441,0.8325,-0.4337,-1.8193,0.9887],[-0.5255,1.3027,-1.1163,0.9153,1.1631],[-1.0639,1,0.5361,-0.0246,-2.2851],[-0.3373,-0.8563,-0.4108,0.4164,-0.4794],[-2.4945,0.2061,0.3174,-0.4102,-1.1696],[0.7484,0.8419,2.9368,0.6293,0.076],[-0.6793,1.6099,-1.2111,0.6299,2.4709],[-0.6371,-0.0523,-0.0753,-0.3741,0.1945],[-0.7409,-0.2696,-0.5928,-0.4269,-0.3832]],"rClass":"matrix","rColClas [...]
+<div id="row-header-width" class="section level3">
+<h3>Row Header Width</h3>
+<p>The width of the row header column can be customized using <code>rowHeaderWidth</code>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">rhandsontable</span>(mtcars, <span class="dt">rowHeaderWidth =</span> <span class="dv">200</span>)</code></pre></div>
+<div id="htmlwidget-4825" style="width:576px;height:576px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-4825">{"x":{"data":[{"mpg":21,"cyl":6,"disp":160,"hp":110,"drat":3.9,"wt":2.62,"qsec":16.46,"vs":0,"am":1,"gear":4,"carb":4},{"mpg":21,"cyl":6,"disp":160,"hp":110,"drat":3.9,"wt":2.875,"qsec":17.02,"vs":0,"am":1,"gear":4,"carb":4},{"mpg":22.8,"cyl":4,"disp":108,"hp":93,"drat":3.85,"wt":2.32,"qsec":18.61,"vs":1,"am":1,"gear":4,"carb":1},{"mpg":21.4,"cyl":6,"disp":258,"hp":110,"drat":3.08,"wt":3.215,"qsec":19.44,"vs":1,"am":0,"gear":3,"c [...]
+</div>
+<div id="streching" class="section level3">
+<h3>Streching</h3>
+<p>The table can be streched to the full width by using <code>stretchH</code>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">30</span>), <span class="dt">nrow =</span> <span class="dv">10</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                                                   letters[<span class="dv">1</span>:<span class="dv">3</span>]))
+
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">width =</span> <span class="dv">600</span>, <span class="dt">height =</span> <span class="dv">300</span>, <span class="dt">stretchH =</span> <span class="st">"all"</span>)</code></pre></div>
+<div id="htmlwidget-8398" style="width:600px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-8398">{"x":{"data":[[-1.1472,-0.216,-0.0085],[0.5,-0.6158,0.1403],[0.7708,-0.7469,1.3659],[1.2522,-0.7034,-0.114],[-2.9471,-0.4832,-0.6507],[-1.2794,-0.3553,0.4003],[1.0148,0.8254,0.1189],[1.7607,0.2764,0.8258],[0.2868,-1.4536,-0.7339],[-0.3946,-0.7151,-0.7149]],"rClass":"matrix","rColClasses":"numeric","rColnames":["a","b","c"],"rColHeaders":["a","b","c"],"rRowHeaders":["A","B","C","D","E","F","G","H","I","J"],"rDataDim":[10,3],"selec [...]
+</div>
+</div>
+<div id="fixed-rows-columns" class="section level2">
+<h2>Fixed Rows / Columns</h2>
+<p>For larger data sets, (multiple) top rows and left columns can be frozen.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">26</span> *<span class="st"> </span><span class="dv">26</span>), <span class="dt">nrow =</span> <span class="dv">26</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS, letters))
+
+<span class="co"># scroll through the table to see the fixed row and column</span>
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_cols</span>(<span class="dt">fixedColumnsLeft =</span> <span class="dv">1</span>) %>%
+<span class="st">  </span><span class="kw">hot_rows</span>(<span class="dt">fixedRowsTop =</span> <span class="dv">1</span>)</code></pre></div>
+<div id="htmlwidget-9978" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-9978">{"x":{"data":[[0.8125,0.2926,-0.1638,0.3146,0.6682,-0.1898,0.2376,-0.0674,0.3385,0.2321,3.3426,-1.5017,-0.1065,0.1188,-0.1353,-0.7408,0.5984,-0.2729,-0.9357,-0.8984,0.7168,0.3243,-1.7634,-0.8069,-0.4111,0.7089],[0.6132,0.1651,0.6424,1.5293,1.089,-1.1196,-0.0442,0.5057,0.0025,-0.8792,-0.4478,-0.0817,-0.0004,-0.4592,0.3462,1.9725,0.1659,0.4045,0.2175,0.8439,0.5557,0.8798,0.518,0.0478,-0.0502,-0.4775],[0.3684,-1.3523,0.0307,0.5454,0 [...]
+</div>
+<div id="cell-comments" class="section level2">
+<h2>Cell Comments</h2>
+<p>Comments (hover) can also be added to individual cells and will appear as red flags in the upper right of the cell.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_cell</span>(<span class="dv">1</span>, <span class="dv">1</span>, <span class="st">"Test comment"</span>)</code></pre></div>
+<div id="htmlwidget-8636" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-8636">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+<p>Additionally, comments can be added via <code>data.frame</code> or <code>matrix</code>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT_comments =<span class="st"> </span><span class="kw">matrix</span>(<span class="dt">ncol =</span> <span class="kw">ncol</span>(DF), <span class="dt">nrow =</span> <span class="kw">nrow</span>(DF))
+MAT_comments[<span class="dv">1</span>, <span class="dv">1</span>] =<span class="st"> "Test comment"</span>
+MAT_comments[<span class="dv">2</span>, <span class="dv">2</span>] =<span class="st"> "Another test comment"</span>
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">comments =</span> MAT_comments, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>)</code></pre></div>
+<div id="htmlwidget-953" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-953">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt": [...]
+<p>Finally, comments can also be added via the right-click context menu, but these updates will not currently be retained by shiny.</p>
+</div>
+<div id="borders" class="section level2">
+<h2>Borders</h2>
+<p>Custom borders can be drawn around cells to highlight specific items. Borders can also be added via the right-click context menu, but these updates will not currently be retained by shiny.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">50</span>), <span class="dt">nrow =</span> <span class="dv">10</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                                                   letters[<span class="dv">1</span>:<span class="dv">5</span>]))
+
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_table</span>(<span class="dt">customBorders =</span> <span class="kw">list</span>(<span class="kw">list</span>(
+    <span class="dt">range =</span> <span class="kw">list</span>(<span class="dt">from =</span> <span class="kw">list</span>(<span class="dt">row =</span> <span class="dv">1</span>, <span class="dt">col =</span> <span class="dv">1</span>),
+                 <span class="dt">to =</span> <span class="kw">list</span>(<span class="dt">row =</span> <span class="dv">2</span>, <span class="dt">col =</span> <span class="dv">2</span>)),
+    <span class="dt">top =</span> <span class="kw">list</span>(<span class="dt">width =</span> <span class="dv">2</span>, <span class="dt">color =</span> <span class="st">"red"</span>),
+    <span class="dt">left =</span> <span class="kw">list</span>(<span class="dt">width =</span> <span class="dv">2</span>, <span class="dt">color =</span> <span class="st">"red"</span>),
+    <span class="dt">bottom =</span> <span class="kw">list</span>(<span class="dt">width =</span> <span class="dv">2</span>, <span class="dt">color =</span> <span class="st">"red"</span>),
+    <span class="dt">right =</span> <span class="kw">list</span>(<span class="dt">width =</span> <span class="dv">2</span>, <span class="dt">color =</span> <span class="st">"red"</span>))))</code></pre></div>
+<div id="htmlwidget-4510" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-4510">{"x":{"data":[[-0.4812,-0.3625,0.1591,2.1902,-0.4746],[0.5916,2.0184,-0.9592,2.0345,-0.3665],[0.2376,-0.2035,-0.3951,-0.3858,-0.302],[-0.3774,0.971,-1.6077,-0.5394,-1.2577],[-0.2219,0.1762,0.6402,0.3303,0.4221],[2.0379,1.5769,-0.618,-0.3038,-1.3415],[1.3503,0.0796,0.5148,0.3019,1.3268],[0.527,1.3489,0.0593,0.6385,-0.092],[-2.2123,1.6397,1.6756,-1.005,0.3463],[0.1732,1.869,0.282,0.5988,-0.7492]],"rClass":"matrix","rColClasses":"nu [...]
+</div>
+<div id="validation" class="section level2">
+<h2>Validation</h2>
+<div id="numeric-columns" class="section level3">
+<h3>Numeric Columns</h3>
+<p>Pre-defined validation can be added for numeric columns in two ways:</p>
+<ul>
+<li>specify a min and max and any values within the range to exclude</li>
+<li>similar to a <code>dropdown</code> column, specify allowed values</li>
+</ul>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">50</span>), <span class="dt">nrow =</span> <span class="dv">10</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                                                   letters[<span class="dv">1</span>:<span class="dv">5</span>]))
+
+<span class="kw">rhandsontable</span>(MAT *<span class="st"> </span><span class="dv">10</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_validate_numeric</span>(<span class="dt">col =</span> <span class="dv">1</span>, <span class="dt">min =</span> -<span class="dv">50</span>, <span class="dt">max =</span> <span class="dv">50</span>, <span class="dt">exclude =</span> <span class="dv">40</span>)</code></pre></div>
+<div id="htmlwidget-8895" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-8895">{"x":{"data":[[-20.7203,-9.4468,7.8944,-2.3686,9.9112],[-6.3772,9.9222,-0.8867,4.0942,-3.2473],[19.1308,-5.0494,6.6914,0.7354,-20.8364],[7.5106,-14.126,-0.7925,-0.0791,0.6919],[11.7244,-11.2351,12.521,-7.0119,0.919],[-0.2537,-9.0314,9.4834,8.2821,7.3945],[6.4536,-19.836,-13.1924,2.2766,4.5959],[8.9099,-10.0401,18.1585,2.8807,-7.2796],[11.1603,18.5998,11.5782,6.1187,1.4123],[-10.9655,-7.7397,8.9213,2.2816,-2.4389]],"rClass":"matri [...]
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">rhandsontable</span>(MAT *<span class="st"> </span><span class="dv">10</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_validate_numeric</span>(<span class="dt">col =</span> <span class="dv">1</span>, <span class="dt">choices =</span> <span class="kw">c</span>(<span class="dv">10</span>, <span class="dv">20</span>, <span class="dv">40</span>))</code></pre></div>
+<div id="htmlwidget-7318" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-7318">{"x":{"data":[[-20.7203,-9.4468,7.8944,-2.3686,9.9112],[-6.3772,9.9222,-0.8867,4.0942,-3.2473],[19.1308,-5.0494,6.6914,0.7354,-20.8364],[7.5106,-14.126,-0.7925,-0.0791,0.6919],[11.7244,-11.2351,12.521,-7.0119,0.919],[-0.2537,-9.0314,9.4834,8.2821,7.3945],[6.4536,-19.836,-13.1924,2.2766,4.5959],[8.9099,-10.0401,18.1585,2.8807,-7.2796],[11.1603,18.5998,11.5782,6.1187,1.4123],[-10.9655,-7.7397,8.9213,2.2816,-2.4389]],"rClass":"matri [...]
+</div>
+<div id="character-columns" class="section level3">
+<h3>Character Columns</h3>
+<p>For character columns, a vector of allowed options can be specified. A more user-friendly approach may be to use a <code>dropdown</code> column with <code>strict = TRUE</code>.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">DF =<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">val =</span> <span class="dv">1</span>:<span class="dv">10</span>, <span class="dt">bool =</span> <span class="ot">TRUE</span>, <span class="dt">big =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">small =</span> letters[<span class="dv">1</span>:<span class="dv">10</span>],
+                <span class="dt">dt =</span> <span class="kw">seq</span>(<span class="dt">from =</span> <span class="kw">Sys.Date</span>(), <span class="dt">by =</span> <span class="st">"days"</span>, <span class="dt">length.out =</span> <span class="dv">10</span>),
+                <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span>)
+
+<span class="kw">rhandsontable</span>(DF, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_validate_character</span>(<span class="dt">col =</span> <span class="st">"big"</span>, <span class="dt">choices =</span> LETTERS[<span class="dv">1</span>:<span class="dv">10</span>])</code></pre></div>
+<div id="htmlwidget-1947" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-1947">{"x":{"data":[{"val":1,"bool":true,"big":"A","small":"a","dt":"11/03/2016"},{"val":2,"bool":true,"big":"B","small":"b","dt":"11/04/2016"},{"val":3,"bool":true,"big":"C","small":"c","dt":"11/05/2016"},{"val":4,"bool":true,"big":"D","small":"d","dt":"11/06/2016"},{"val":5,"bool":true,"big":"E","small":"e","dt":"11/07/2016"},{"val":6,"bool":true,"big":"F","small":"f","dt":"11/08/2016"},{"val":7,"bool":true,"big":"G","small":"g","dt" [...]
+</div>
+<div id="custom" class="section level3">
+<h3>Custom</h3>
+<p>It is also possible to create a custom validation function in JavaScript.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">50</span>), <span class="dt">nrow =</span> <span class="dv">10</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                                                   letters[<span class="dv">1</span>:<span class="dv">5</span>]))
+
+<span class="co"># try to update any cell to 0</span>
+<span class="kw">rhandsontable</span>(MAT *<span class="st"> </span><span class="dv">10</span>, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_cols</span>(<span class="dt">validator =</span> <span class="st">"</span>
+<span class="st">           function (value, callback) {</span>
+<span class="st">            setTimeout(function(){</span>
+<span class="st">              callback(value != 0);</span>
+<span class="st">            }, 1000)</span>
+<span class="st">           }"</span>,
+           <span class="dt">allowInvalid =</span> <span class="ot">FALSE</span>)</code></pre></div>
+<div id="htmlwidget-4716" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-4716">{"x":{"data":[[-8.5531,5.3836,5.9359,-3.8231,-12.34],[6.428,3.7607,-4.5225,3.1724,-24.0245],[-12.4708,-21.9432,-17.7899,-2.1041,-2.5938],[1.2009,14.6189,6.0241,-3.8441,-5.5378],[-17.2635,-3.1752,-4.0962,-3.3101,32.3152],[0.62,3.9652,3.865,12.3313,-7.2068],[-14.2079,9.6314,6.1127,-4.8261,-3.0119],[0.6911,-3.0272,-16.9344,-15.2254,-6.7713],[4.3706,-5.907,-21.6954,8.7758,-1.1019],[14.0572,6.7902,6.0542,1.5492,-7.2491]],"rClass":"mat [...]
+</div>
+</div>
+<div id="conditional-formatting" class="section level2">
+<h2>Conditional Formatting</h2>
+<p>Conditional formatting can also be specified via custom JavaScript function. Future enhancements will look to simplify this interface.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">runif</span>(<span class="dv">100</span>, -<span class="dv">1</span>, <span class="dv">1</span>), <span class="dt">nrow =</span> <span class="dv">10</span>,
+             <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>], LETTERS[<span class="dv">1</span>:<span class="dv">10</span>]))
+<span class="kw">diag</span>(MAT) =<span class="st"> </span><span class="dv">1</span>
+MAT[<span class="kw">upper.tri</span>(MAT)] =<span class="st"> </span>MAT[<span class="kw">lower.tri</span>(MAT)]
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">readOnly =</span> <span class="ot">TRUE</span>, <span class="dt">width =</span> <span class="dv">750</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_cols</span>(<span class="dt">renderer =</span> <span class="st">"</span>
+<span class="st">           function (instance, td, row, col, prop, value, cellProperties) {</span>
+<span class="st">             Handsontable.renderers.TextRenderer.apply(this, arguments);</span>
+<span class="st">             if (row == col) {</span>
+<span class="st">              td.style.background = 'lightgrey';</span>
+<span class="st">             } else if (col > row) {</span>
+<span class="st">              td.style.background = 'grey';</span>
+<span class="st">              td.style.color = 'grey';</span>
+<span class="st">             } else if (value < -0.75) {</span>
+<span class="st">              td.style.background = 'pink';</span>
+<span class="st">             } else if (value > 0.75) {</span>
+<span class="st">              td.style.background = 'lightgreen';</span>
+<span class="st">             }</span>
+<span class="st">           }"</span>)</code></pre></div>
+<div id="htmlwidget-5438" style="width:750px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-5438">{"x":{"data":[[1,0.1844,-0.7149,-0.5958,0.9915,-0.1044,-0.2469,0.5822,0.7499,0.3693],[0.1844,1,0.4126,-0.7519,-0.9436,0.2757,-0.0199,-0.2359,0.8376,0.5562],[-0.7149,0.7561,1,0.2864,0.7422,0.2314,0.7966,-0.034,-0.7357,0.2102],[0.4126,-0.1044,0.7966,1,0.7561,-0.9627,0.8655,0.3297,0.1773,0.4837],[-0.5958,0.2757,0.8655,0.3297,1,-0.2001,0.0643,0.5156,0.7818,-0.3743],[-0.7519,0.2314,0.0643,0.5156,-0.7357,1,0.1882,-0.8408,0.8054,0.8744] [...]
+<p>See <a href="#custom_renderer_using_r">Custom Renderer using an R Parameter</a> for anotehr example.</p>
+</div>
+<div id="heatmap" class="section level2">
+<h2>Heatmap</h2>
+<p>The <a href="http://old.driven-by-data.net/about/chromajs/">chroma.js</a> library can be used to turn the table into a heatmap.</p>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">50</span>), <span class="dt">nrow =</span> <span class="dv">10</span>, <span class="dt">dimnames =</span> <span class="kw">list</span>(LETTERS[<span class="dv">1</span>:<span class="dv">10</span>],
+                                                   letters[<span class="dv">1</span>:<span class="dv">5</span>]))
+
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">300</span>) %>%
+<span class="st">  </span><span class="kw">hot_heatmap</span>()</code></pre></div>
+<div id="htmlwidget-6050" style="width:550px;height:300px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-6050">{"x":{"data":[[-0.1331,0.291,0.3097,1.0926,-0.6644],[-1.2994,0.8499,0.0136,-0.6436,0.5012],[-1.4079,-1.4704,-1.0464,-2.154,-0.9813],[-1.2354,-0.5259,0.693,0.3157,-1.0299],[-1.1389,-0.5835,-0.7734,1.2885,0.5063],[1.6061,1.1502,-0.8548,-0.9631,-0.311],[0.1752,1.3889,2.5713,0.593,-0.9038],[-1.4561,0.7959,-0.1373,-0.6345,0.7528],[0.0113,-0.0584,0.613,-1.0618,0.7302],[-0.8186,-1.3591,-0.4398,-0.2387,1.5417]],"rClass":"matrix","rColCla [...]
+</div>
+<div id="big-data" class="section level2">
+<h2>Big Data</h2>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">MAT =<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="dv">10000</span> *<span class="st"> </span><span class="dv">100</span>), <span class="dt">nrow =</span> <span class="dv">100</span>, <span class="dt">dimnames=</span> <span class="kw">list</span>(<span class="dv">1</span>:<span class="dv">100</span>, <span class="dv">1</span>:<span class="dv">10000</span>))
+
+<span class="kw">rhandsontable</span>(MAT, <span class="dt">width =</span> <span class="dv">550</span>, <span class="dt">height =</span> <span class="dv">550</span>)</code></pre></div>
+<div id="htmlwidget-2138" style="width:550px;height:550px;" class="rhandsontable html-widget"></div>
+<script type="application/json" data-for="htmlwidget-2138">{"x":{"data":[[1.3067,-1.3632,2.1427,0.4601,1.4308,0.0924,-0.8052,-1.2356,0.4939,-0.535,-0.2209,-0.4449,-0.0899,0.8264,0.1703,-0.8386,1.3764,-0.413,0.8528,0.1851,0.7206,0.2784,1.1172,0.5427,-0.9444,-2.2794,-0.4806,0.6104,-0.6265,0.7685,1.1315,-1.4036,0.8792,0.1099,-0.8796,-0.2848,-1.9298,1.1611,0.1466,-0.5989,1.1463,0.315,0.3137,-0.8103,-0.7235,1.3818,0.7344,-0.5572,-0.7418,-0.4645,1.3288,0.6618,-1.1826,1.0748,1.0675,-1.3897,-1.8 [...]
+</div>
+<div id="shiny" class="section level2">
+<h2>Shiny</h2>
+<p><strong>Important note on shiny use:</strong> The <code>htmlwidgets</code> package creates widgets as shiny output bindings. The <code>rhandsontable</code> package also attempts to expose the table as a <em>pseudo</em> shiny input binding using handsontable change events (see <a href="https://github.com/jrowen/rhandsontable/blob/master/inst/htmlwidgets/rhandsontable.js">here</a> for the supported events). <strong>This means the table (e.g. <code>hot</code>) can be accessed in shiny us [...]
+<p>Since the widget is not currently able to use the standard shiny input binding functionality, you will need to explicitly call the <code>hot_to_r</code> function to convert the handsontable data to an R object.</p>
+<p>Two additional inputs are also enabled, <code>input$hot_select</code> and <code>input$hot_comment</code>, which will fire when a cell selection or a comment changes, respectively (if you would like to see more options, please post an issue or create a PR).</p>
+<p>This functionality is still evolving, so please don’t hesitate to share suggestions and PRs.</p>
+<p>The data grid will be editable by default and can be used as input to a <code>shiny</code> app. A few <code>shiny</code> and <code>shinydashboard</code> example links are listed below. Note that the shinyapps.io links may not work if the has hit the monthly usage limit.</p>
+<ul>
+<li><p><a href="https://jrowen.shinyapps.io/rhandsontable_output">Output only</a></p>
+<pre><code>shiny::runGitHub("rhandsontable", "jrowen", 
+             subdir = "inst/examples/rhandsontable_output")</code></pre></li>
+<li><p><a href="https://jrowen.shinyapps.io/rhandsontable_datafile">Date file editor</a></p>
+<pre><code>shiny::runGitHub("rhandsontable", "jrowen", 
+             subdir = "inst/examples/rhandsontable_datafile")</code></pre></li>
+<li><p><a href="https://jrowen.shinyapps.io/rhandsontable_portfolio">Calculation input</a></p>
+<pre><code>shiny::runGitHub("rhandsontable", "jrowen", 
+             subdir = "inst/examples/rhandsontable_portfolio")</code></pre></li>
+<li><p><a href="https://jrowen.shinyapps.io/rhandsontable_corr">Table callback linked to chart</a></p>
+<pre><code>shiny::runGitHub("rhandsontable", "jrowen", 
+             subdir = "inst/examples/rhandsontable_corr")</code></pre></li>
+<li><p><a href="https://jrowen.shinyapps.io/rhandsontable_frontier">Multiple input tables</a></p>
+<pre><code>shiny::runGitHub("rhandsontable", "jrowen", 
+             subdir = "inst/examples/rhandsontable_frontier")</code></pre></li>
+<li><p><a href="https://jrowen.shinyapps.io/rhandsontable_dash">A shinydashboard app</a></p>
+<pre><code>shiny::runGitHub("rhandsontable", "jrowen", 
+             subdir="inst/examples/rhandsontable_dash")</code></pre></li>
+</ul>
+<div id="bookmarks" class="section level3">
+<h3>Bookmarks</h3>
+<p>Version 0.14 of <code>shiny</code> includes new bookmarking functionality. This willl work for <code>rhandsontable</code> with some special handling. See <a href="https://github.com/rstudio/shiny/issues/1378">this issue</a> for more details.</p>
+</div>
+</div>
+<div id="suggestions-contributions" class="section level2">
+<h2>Suggestions & Contributions</h2>
+<p>Please file a issue if you experience any problems with the widget or have feature requests. Pull requests are also welcome.</p>
+</div>
+
+
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+  (function () {
+    var script = document.createElement("script");
+    script.type = "text/javascript";
+    script.src  = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+    document.getElementsByTagName("head")[0].appendChild(script);
+  })();
+</script>
+
+</body>
+</html>
diff --git a/inst/htmlwidgets/lib/chroma/chroma.min.js b/inst/htmlwidgets/lib/chroma/chroma.min.js
new file mode 100644
index 0000000..546051e
--- /dev/null
+++ b/inst/htmlwidgets/lib/chroma/chroma.min.js
@@ -0,0 +1,33 @@
+/*
+chroma.js - JavaScript library for color conversions
+
+Copyright (c) 2011-2015, Gregor Aisch
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. The name Gregor Aisch may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,aa,ba,ca,da,ea,fa,ga,ha,ia,ja,ka,la,ma,na,oa,pa,qa,ra,sa,ta,ua,va,wa,xa,ya,za=[].slice;ua=function(){var a,b,c,d,e;for(a={},e="Boolean Number String Function Array Date RegExp Undefined Null".split(" "),d=0,b=e.length;b>d;d++)c=e[d],a["[object "+c+"]"]=c.toLowerCase();return function(b){var c;return c=Object.prototype.toString.call(b),a[c]||"object"}}(),S=function(a [...]
+},k.push(["lab",J])}).call(this);
\ No newline at end of file
diff --git a/inst/htmlwidgets/lib/handsontable/handsontable.full.min.css b/inst/htmlwidgets/lib/handsontable/handsontable.full.min.css
new file mode 100644
index 0000000..1a49e9e
--- /dev/null
+++ b/inst/htmlwidgets/lib/handsontable/handsontable.full.min.css
@@ -0,0 +1,31 @@
+ at charset "UTF-8";/*!
+(The MIT License)
+
+Copyright (c) 2012-2014 Marcin Warpechowski
+Copyright (c) 2015 Handsoncode sp. z o.o. <hello at handsoncode.net>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/.handsontable{position:relative}.handsontable .hide{display:none}.handsontable .relative{position:relative}.handsontable.htAutoSize{visibility:hidden;left:-99000px;position:absolute;top:-99000px}.handsontable .wtHider{width:0}.handsontable .wtSpreader{position:relative;width:0;height:auto}.handsontable table,.handsontable tbody,.handsontable thead,.handsontable td,.handsontable th,.handsontable input,.handsontable textarea,.handsontable div{box-sizing:content-box;-webkit-box-sizing:con [...]
+ * Handsontable ContextMenu
+ */.htContextMenu{display:none;position:absolute;z-index:1060}.htContextMenu .ht_clone_top,.htContextMenu .ht_clone_left,.htContextMenu .ht_clone_corner,.htContextMenu .ht_clone_debug{display:none}.htContextMenu table.htCore{border:1px solid #ccc;border-bottom-width:2px;border-right-width:2px}.htContextMenu .wtBorder{visibility:hidden}.htContextMenu table tbody tr td{background:white;border-width:0;padding:4px 6px 0 6px;cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:elli [...]
+ * Pikaday
+ * Copyright © 2014 David Bushell | BSD & MIT license | http://dbushell.com/
+ */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:before,.pika-single:after{content:" ";display:table}.pika-single:after{clear:both}.pika-single{*zoom:1}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position [...]
\ No newline at end of file
diff --git a/inst/htmlwidgets/lib/handsontable/handsontable.full.min.js b/inst/htmlwidgets/lib/handsontable/handsontable.full.min.js
new file mode 100644
index 0000000..7f4cd71
--- /dev/null
+++ b/inst/htmlwidgets/lib/handsontable/handsontable.full.min.js
@@ -0,0 +1,89 @@
+/*!
+(The MIT License)
+
+Copyright (c) 2012-2014 Marcin Warpechowski
+Copyright (c) 2015 Handsoncode sp. z o.o. <hello at handsoncode.net>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Handsontable=e()}}(function(){var e;return function e(t,o,n){function r(a,l){if(!o[a]){if(!t[a]){var u="function"==typeof require&&require;if(!l&&u)return u(a,!0);if(i)return i(a,!0);if(s[a]&&"undefined"!=typeof window[s[a]])re [...]
+return this.unOffsetted(e)},offsettedTH:function(e){return e-this.countTH},unOffsettedTH:function(e){return e+this.countTH},visibleRowHeadedColumnToSourceColumn:function(e){return this.renderedToSource(this.offsettedTH(e))},sourceColumnToVisibleRowHeadedColumn:function(e){return this.unOffsettedTH(this.sourceToRendered(e))}},{}),window.WalkontableColumnFilter=n},{}],11:[function(e,t,o){"use strict";Object.defineProperties(o,{WalkontableRowFilter:{get:function(){return n}},__esModule:{val [...]
+var c=[];this.settings.highlightHeaderClassName&&c.push(this.settings.highlightHeaderClassName),this.settings.highlightColumnClassName&&c.push(this.settings.highlightColumnClassName),a(r,c)}for(var h=0;h<i;h++){if(o=e.wtTable.rowFilter.renderedToSource(h),o>=l[0]&&o<=l[2]&&(r=e.wtTable.getRowHeader(o))){var d=[];this.settings.highlightHeaderClassName&&d.push(this.settings.highlightHeaderClassName),this.settings.highlightRowClassName&&d.push(this.settings.highlightRowClassName),a(r,d)}for [...]
+i&&i.__esModule&&i||{default:i};var O=(s=e("pluginHooks"),s&&s.__esModule&&s||{default:s}).Hooks,k=(a=e("numbro"),a&&a.__esModule&&a||{default:a}).default,x=(l=e("moment"),l&&l.__esModule&&l||{default:l}).default;"object"==typeof window&&("undefined"==typeof window.numbro&&(window.numbro=k),"undefined"==typeof window.moment&&(window.moment=x)),n.hooks||(n.hooks=new O),n.utils.Hooks=O,u=e("core"),u&&u.__esModule&&u||{default:u},c=e("renderers/_cellDecorator"),c&&c.__esModule&&c||{default: [...]
+var t=l.settings.rowHeaders;return void 0!==e&&(e=E.hooks.run(p,"modifyRowHeader",e)),void 0===e?(t=[],te(p.countRows()-1,function(e){t.push(p.getRowHeader(e))})):Array.isArray(t)&&void 0!==t[e]?t=t[e]:P(t)?t=t(e):t&&"string"!=typeof t&&"number"!=typeof t&&(t=e+1),t},this.hasRowHeaders=function(){return!!l.settings.rowHeaders},this.hasColHeaders=function(){if(void 0!==l.settings.colHeaders&&null!==l.settings.colHeaders)return!!l.settings.colHeaders;for(var e=0,t=p.countCols();e<t;e++)if( [...]
+browser:24,"helpers/mixed":51}],32:[function(e,t,o){"use strict";function n(e){O=!1;var t=this.getActiveEditor();if(d(e.keyCode)||e.keyCode===h.BACKSPACE||e.keyCode===h.DELETE||e.keyCode===h.INSERT){var o=0;if(e.keyCode===h.C&&(e.ctrlKey||e.metaKey))return;t.isOpened()||(o+=10),t.htEditor&&t.instance._registerTimeout(setTimeout(function(){t.queryChoices(t.TEXTAREA.value),O=!0},o))}}Object.defineProperties(o,{AutocompleteEditor:{get:function(){return T}},__esModule:{value:!0}});var r,i,s, [...]
+break;case x.ENTER:var r=n.instance.getSelected(),i=!(r[0]===r[2]&&r[1]===r[3]);if(t&&!i||e.altKey){if(n.isOpened()){var s=p(n.TEXTAREA),a=n.getValue(),l=a.slice(0,s)+"\n"+a.slice(s);n.setValue(l),_(n.TEXTAREA,s+1)}else n.beginEditing(n.originalValue+"\n");A(e)}e.preventDefault();break;case x.A:case x.X:case x.C:case x.V:t&&A(e);break;case x.BACKSPACE:case x.DELETE:case x.HOME:case x.END:A(e)}[x.ARROW_UP,x.ARROW_RIGHT,x.ARROW_DOWN,x.ARROW_LEFT].indexOf(e.keyCode)===-1&&n.autoResize.resiz [...]
+Object.defineProperty(e,t,n)}function p(e,t){for(var o in e)if((!e.hasOwnProperty||e.hasOwnProperty&&e.hasOwnProperty(o))&&t(e[o],o,e)===!1)break;return e}function g(e,t){var o=t.split("."),n=e;return p(o,function(e){if(n=n[e],void 0===n)return n=void 0,!1}),n}function m(e){if(!h(e))return 0;var t=function(e){var o=0;return h(e)?p(e,function(e){o+=t(e)}):o++,o};return t(e)}function w(e){var t,o=void 0!==arguments[1]?arguments[1]:"value",n="_"+o,r=(t={},Object.defineProperty(t,"_touched", [...]
+t=this.instance.getData();e:for(o=e[2]+1;o<this.instance.countRows();o++){for(r=e[1];r<=e[3];r++)if(t[o][r])break e;(t[o][e[1]-1]||t[o][e[3]+1])&&(n=o)}n&&(this.instance.view.wt.selections.fill.clear(),this.instance.view.wt.selections.fill.add(new w(e[0],e[1])),this.instance.view.wt.selections.fill.add(new w(n,e[3])),this.apply())},r.prototype.apply=function(){var e,t,o,r,i,s,a,l;this.handle.isDragged=0,this.instance.view.wt.selections.fill.isEmpty()||(e=this.instance.view.wt.selections. [...]
+t.fitsOnRight(this.container)?this.setPositionOnRightOfCursor(t):this.setPositionOnLeftOfCursor(t)):(this.setPositionBelowCursor(t),this.setPositionOnRightOfCursor(t))},setPositionAboveCursor:function(e){var t=this.offset.above+e.top-this.container.offsetHeight;this.isSubMenu()&&(t=e.top+e.cellHeight-this.container.offsetHeight+3),this.container.style.top=t+"px"},setPositionBelowCursor:function(e){var t=this.offset.below+e.top;this.isSubMenu()&&(t=e.top-1),this.container.style.top=t+"px" [...]
+for(var n=e.from.col;n<=e.to.col;n++)for(var r=e.from.row;r<=e.to.row;r++)M.call(this,r,n);break;case"top":for(var i=e.from.col;i<=e.to.col;i++)E.call(this,e.from.row,i,t,o);break;case"right":for(var s=e.from.row;s<=e.to.row;s++)E.call(this,s,e.to.col,t);break;case"bottom":for(var a=e.from.col;a<=e.to.col;a++)E.call(this,e.to.row,a,t);break;case"left":for(var l=e.from.row;l<=e.to.row;l++)E.call(this,l,e.from.col,t)}},O=function(e,t){var o=!1;return e.getSelectedRange().forAll(function(n, [...]
+},getRowsHeight:function(e,t){for(var o=0,n=e;n<t;n++){var r=this.hot.view.wt.wtTable.getRowHeight(n)||23;o+=r}return o},initialSettings:function(){var e=this.hot.getSettings().manualRowMove;if(Array.isArray(e))this.moveRows(e,0);else if(void 0!==e){var t=this.persistentStateLoad();t.length&&this.moveRows(t,0)}},isFixedRowTop:function(e){return e<this.hot.getSettings().fixedRowsTop},isFixedRowBottom:function(e){return e>this.hot.getSettings().fixedRowsBottom},persistentStateSave:function [...]
+i&&i.__esModule&&i||{default:i}).default,(s=e("dataObserver"),s&&s.__esModule&&s||{default:s}).DataObserver),d=(a=e("helpers/array"),a&&a.__esModule&&a||{default:a}).arrayEach,f=(l=e("plugins"),l&&l.__esModule&&l||{default:l}).registerPlugin;u.hooks.register("afterChangesObserved");var p=function(e){$traceurRuntime.superConstructor(g).call(this,e),this.observer=null},g=p;$traceurRuntime.createClass(p,{isEnabled:function(){return this.hot.getSettings().observeChanges},enablePlugin:functio [...]
+M(a.prototype,"toString",H(function(){var e=this[L];if(!p("symbols"))return e[A];if(!e)throw TypeError("Conversion from symbol to string");var t=e[P];return void 0===t&&(t=""),"Symbol("+t+")"})),M(a.prototype,"valueOf",H(function(){var e=this[L];if(!e)throw TypeError("Conversion from symbol to string");return p("symbols")?e:e[A]})),M(l.prototype,"constructor",t(a)),M(l.prototype,"toString",{value:a.prototype.toString,enumerable:!1}),M(l.prototype,"valueOf",{value:a.prototype.valueOf,enum [...]
+t.style.overflowY="visible"):t.style.height=l+"px"},u=function(){window.setTimeout(l,0)},c=function(e){if(e&&e.minHeight)if("inherit"==e.minHeight)o.minHeight=t.clientHeight;else{var n=parseInt(e.minHeight);isNaN(n)||(o.minHeight=n)}if(e&&e.maxHeight)if("inherit"==e.maxHeight)o.maxHeight=t.clientHeight;else{var s=parseInt(e.maxHeight);isNaN(s)||(o.maxHeight=s)}if(e&&e.minWidth)if("inherit"==e.minWidth)o.minWidth=t.clientWidth;else{var a=parseInt(e.minWidth);isNaN(a)||(o.minWidth=a)}if(e& [...]
+ * Copyright (C) 2011 by Andrea Giammarchi, @WebReflection
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+!function(e){"use strict";function t(e,t){function n(e){return this&&this.constructor===n?(this._keys=[],this._values=[],this._itp=[],this.objectOnly=t,void(e&&o.call(this,e))):new n(e)}return t||y(e,"size",{get:m}),e.constructor=n,n.prototype=e,n}function o(e){this.add?e.forEach(this.add,this):e.forEach(function(e){this.set(e[0],e[1])},this)}function n(e){return this.has(e)&&(this._keys.splice(v,1),this._values.splice(v,1),this._itp.forEach(function(e){v<e[0]&&e[0]--})),-1<v}function r( [...]
+ * https://github.com/Starcounter-Jack/JSON-Patch
+ * json-patch-duplex.js version: 0.5.7
+ * (c) 2013 Joachim Wester
+ * MIT license
+ */
+var n,r=this&&this.__extends||function(e,t){function o(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(o.prototype=t.prototype,new o)},i=Error;!function(e){function t(e,o){switch(typeof e){case"undefined":case"boolean":case"string":case"number":return e===o;case"object":if(null===e)return null===o;if(E(e)){if(!E(o)||e.length!==o.length)return!1;for(var n=0,r=e.length;n<r;n++)if(!t(e[n],o[n]))return!1;return!0}var i=y(o),s=i.leng [...]
+var e=Tt(Kn,this._i);0===e?this.utcOffset(0,!0):this.utcOffset(Tt(Kn,this._i))}return this}function Lt(e){return!!this.isValid()&&(e=e?yt(e).utcOffset():0,(this.utcOffset()-e)%60===0)}function Nt(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function It(){if(!m(this._isDSTShifted))return this._isDSTShifted;var e={};if(w(e,this),e=mt(e),e._a){var t=e._isUTC?h(e._a):yt(e._a);this._isDSTShifted=this.isValid()&&_(e._a,t.toArra [...]
+ * numbro.js
+ * version : 1.9.3
+ * author : Företagsplatsen AB
+ * license : MIT
+ * http://www.foretagsplatsen.se
+ */
+(function(){"use strict";function n(e){this._value=e}function r(e){var t,o="";for(t=0;t<e;t++)o+="0";return o}function i(e,t){var o,n,i,s,a,l,u,c;return c=e.toString(),o=c.split("e")[0],s=c.split("e")[1],n=o.split(".")[0],i=o.split(".")[1]||"",+s>0?c=n+i+r(s-i.length):(a=+n<0?"-0":"0",t>0&&(a+="."),u=r(-1*s-1),l=(u+Math.abs(n)+i).substr(0,t),c=a+l),+s>0&&t>0&&(c+="."+r(t)),c}function s(e,t,o,n){var r,s,a=Math.pow(10,t);return e.toString().indexOf("e")>-1?(s=i(e,t),"-"===s.charAt(0)&&+s>= [...]
+ * Pikaday
+ *
+ * Copyright © 2014 David Bushell | BSD & MIT license | https://github.com/dbushell/Pikaday
+ */
+!function(r,i){"use strict";var s;if("object"==typeof n){try{s=t("moment")}catch(e){}o.exports=i(s)}else"function"==typeof e&&e.amd?e(function(e){var t="moment";try{s=e(t)}catch(e){}return i(s)}):r.Pikaday=i(r.moment)}(this,function(e){"use strict";var t="function"==typeof e,o=!!window.addEventListener,n=window.document,r=window.setTimeout,i=function(e,t,n,r){o?e.addEventListener(t,n,!!r):e.attachEvent("on"+t,n)},s=function(e,t,n,r){o?e.removeEventListener(t,n,!!r):e.detachEvent("on"+t,n [...]
+ * ZeroClipboard
+ * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.
+ * Copyright (c) 2009-2014 Jon Rohan, James M. Greene
+ * Licensed MIT
+ * http://zeroclipboard.org/
+ * v2.2.0
+ */
+!function(t,n){"use strict";var r,i,s,a=t,l=a.document,u=a.navigator,c=a.setTimeout,h=a.clearTimeout,d=a.setInterval,f=a.clearInterval,p=a.getComputedStyle,g=a.encodeURIComponent,m=a.ActiveXObject,w=a.Error,v=a.Number.parseInt||a.parseInt,y=a.Number.parseFloat||a.parseFloat,b=a.Number.isNaN||a.isNaN,C=a.Date.now,_=a.Object.keys,R=a.Object.defineProperty,S=a.Object.prototype.hasOwnProperty,M=a.Array.prototype.slice,E=function(){var e=function(e){return e};if("function"==typeof a.wrap&&"fu [...]
\ No newline at end of file
diff --git a/inst/htmlwidgets/lib/jquery/jquery.min.js b/inst/htmlwidgets/lib/jquery/jquery.min.js
new file mode 100644
index 0000000..349030d
--- /dev/null
+++ b/inst/htmlwidgets/lib/jquery/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v2.2.1 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r= [...]
+}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.came [...]
+e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):cb.test(a.nodeName)||db.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength [...]
diff --git a/inst/htmlwidgets/lib/numbro/languages.js b/inst/htmlwidgets/lib/numbro/languages.js
new file mode 100644
index 0000000..d24b9b1
--- /dev/null
+++ b/inst/htmlwidgets/lib/numbro/languages.js
@@ -0,0 +1,1932 @@
+/*!
+ * numbro.js language configuration
+ * language : Czech
+ * locale: Czech Republic
+ * author : Anatoli Papirovski : https://github.com/apapirovski
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'cs-CZ',
+        cultureCode: 'cs-CZ',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'tis.',
+            million: 'mil.',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: 'Kč',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Danish
+ * locale: Denmark
+ * author : Michael Storgaard : https://github.com/mstorgaard
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'da-DK',
+        cultureCode: 'da-DK',
+        delimiters: {
+            thousands: '.',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'mio',
+            billion: 'mia',
+            trillion: 'b'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: 'kr',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : German
+ * locale: Switzerland
+ * author : Michael Piefel : https://github.com/piefel (based on work from Marco Krage : https://github.com/sinky)
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'de-CH',
+        cultureCode: 'de-CH',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: 'CHF',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : German
+ * locale: Germany
+ * author : Marco Krage : https://github.com/sinky
+ *
+ * Generally useful in Germany, Austria, Luxembourg, Belgium
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'de-DE',
+        cultureCode: 'de-DE',
+        delimiters: {
+            thousands: '.',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : English
+ * locale: Australia
+ * author : Benedikt Huss : https://github.com/ben305
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'en-AU',
+        cultureCode: 'en-AU',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function (number) {
+            var b = number % 10;
+            return (~~ (number % 100 / 10) === 1) ? 'th' :
+                (b === 1) ? 'st' :
+                (b === 2) ? 'nd' :
+                (b === 3) ? 'rd' : 'th';
+        },
+        currency: {
+            symbol: '$',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '$ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '$ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : English
+ * locale: United Kingdom of Great Britain and Northern Ireland
+ * author : Dan Ristic : https://github.com/dristic
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'en-GB',
+        cultureCode: 'en-GB',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function (number) {
+            var b = number % 10;
+            return (~~ (number % 100 / 10) === 1) ? 'th' :
+                (b === 1) ? 'st' :
+                (b === 2) ? 'nd' :
+                (b === 3) ? 'rd' : 'th';
+        },
+        currency: {
+            symbol: '£',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '$ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '$ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : English
+ * locale: New Zealand
+ * author : Benedikt Huss : https://github.com/ben305
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'en-NZ',
+        cultureCode: 'en-NZ',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function (number) {
+            var b = number % 10;
+            return (~~ (number % 100 / 10) === 1) ? 'th' :
+                (b === 1) ? 'st' :
+                (b === 2) ? 'nd' :
+                (b === 3) ? 'rd' : 'th';
+        },
+        currency: {
+            symbol: '$',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '$ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '$ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : English
+ * locale: South Africa
+ * author : Stewart Scott https://github.com/stewart42
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'en-ZA',
+        cultureCode: 'en-ZA',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function (number) {
+            var b = number % 10;
+            return (~~ (number % 100 / 10) === 1) ? 'th' :
+                (b === 1) ? 'st' :
+                (b === 2) ? 'nd' :
+                (b === 3) ? 'rd' : 'th';
+        },
+        currency: {
+            symbol: 'R',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '$ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '$ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Spanish
+ * locale: Argentina
+ * author : Hernan Garcia : https://github.com/hgarcia
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'es-AR',
+        cultureCode: 'es-AR',
+        delimiters: {
+            thousands: '.',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'mm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function (number) {
+            var b = number % 10;
+            return (b === 1 || b === 3) ? 'er' :
+                (b === 2) ? 'do' :
+                (b === 7 || b === 0) ? 'mo' :
+        (b === 8) ? 'vo' :
+        (b === 9) ? 'no' : 'to';
+        },
+        currency: {
+            symbol: '$',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Spanish
+ * locale: Spain
+ * author : Hernan Garcia : https://github.com/hgarcia
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'es-ES',
+        cultureCode: 'es-ES',
+        delimiters: {
+            thousands: '.',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'mm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function (number) {
+            var b = number % 10;
+            return (b === 1 || b === 3) ? 'er' :
+                (b === 2) ? 'do' :
+                    (b === 7 || b === 0) ? 'mo' :
+                        (b === 8) ? 'vo' :
+                            (b === 9) ? 'no' : 'to';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Estonian
+ * locale: Estonia
+ * author : Illimar Tambek : https://github.com/ragulka
+ *
+ * Note: in Estonian, abbreviations are always separated
+ * from numbers with a space
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'et-EE',
+        cultureCode: 'et-EE',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: ' tuh',
+            million: ' mln',
+            billion: ' mld',
+            trillion: ' trl'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Farsi
+ * locale: Iran
+ * author : neo13 : https://github.com/neo13
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'fa-IR',
+        cultureCode: 'fa-IR',
+        delimiters: {
+            thousands: '،',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'هزار',
+            million: 'میلیون',
+            billion: 'میلیارد',
+            trillion: 'تریلیون'
+        },
+        ordinal: function () {
+            return 'ام';
+        },
+        currency: {
+            symbol: '﷼'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Finnish
+ * locale: Finland
+ * author : Sami Saada : https://github.com/samitheberber
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'fi-FI',
+        cultureCode: 'fi-FI',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'M',
+            billion: 'G',
+            trillion: 'T'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Filipino (Pilipino)
+ * locale: Philippines
+ * author : Michael Abadilla : https://github.com/mjmaix
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'fil-PH',
+        cultureCode: 'fil-PH',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function (number) {
+            var b = number % 10;
+            return (~~ (number % 100 / 10) === 1) ? 'th' :
+                (b === 1) ? 'st' :
+                (b === 2) ? 'nd' :
+                (b === 3) ? 'rd' : 'th';
+        },
+        currency: {
+            symbol: '₱'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : French
+ * locale: Canada
+ * author : Léo Renaud-Allaire : https://github.com/renaudleo
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'fr-CA',
+        cultureCode: 'fr-CA',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'M',
+            billion: 'G',
+            trillion: 'T'
+        },
+        ordinal : function (number) {
+            return number === 1 ? 'er' : 'ème';
+        },
+        currency: {
+            symbol: '$',
+            position: 'postfix',
+            spaceSeparated : true
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '$ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '$ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : French
+ * locale: Switzerland
+ * author : Adam Draper : https://github.com/adamwdraper
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'fr-CH',
+        cultureCode: 'fr-CH',
+        delimiters: {
+            thousands: '\'',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal : function (number) {
+            return number === 1 ? 'er' : 'ème';
+        },
+        currency: {
+            symbol: 'CHF',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : French
+ * locale: France
+ * author : Adam Draper : https://github.com/adamwdraper
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'fr-FR',
+        cultureCode: 'fr-FR',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal : function (number) {
+            return number === 1 ? 'er' : 'ème';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Hebrew
+ * locale : IL
+ * author : Eli Zehavi : https://github.com/eli-zehavi
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'he-IL',
+        cultureCode: 'he-IL',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'אלף',
+            million: 'מליון',
+            billion: 'בליון',
+            trillion: 'טריליון'
+        },
+        currency: {
+            symbol: '₪',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '₪ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '₪ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+
+/*!
+ * numbro.js language configuration
+ * language : Hungarian
+ * locale: Hungary
+ * author : Peter Bakondy : https://github.com/pbakondy
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'hu-HU',
+        cultureCode: 'hu-HU',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'E',  // ezer
+            million: 'M',   // millió
+            billion: 'Mrd', // milliárd
+            trillion: 'T'   // trillió
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: ' Ft',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Italian
+ * locale: Italy
+ * author : Giacomo Trombi : http://cinquepunti.it
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'it-IT',
+        cultureCode: 'it-IT',
+        delimiters: {
+            thousands: '.',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'mila',
+            million: 'mil',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            return 'º';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Japanese
+ * locale: Japan
+ * author : teppeis : https://github.com/teppeis
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'ja-JP',
+        cultureCode: 'ja-JP',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: '千',
+            million: '百万',
+            billion: '十億',
+            trillion: '兆'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '¥',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '$ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '$ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Korean
+ * author (numbro.js Version): Randy Wilander : https://github.com/rocketedaway
+ * author (numeral.js Version) : Rich Daley : https://github.com/pedantic-git
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'ko-KR',
+        cultureCode: 'ko-KR',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: '천',
+            million: '백만',
+            billion: '십억',
+            trillion: '일조'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '₩'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Latvian
+ * locale: Latvia
+ * author : Lauris Bukšis-Haberkorns : https://github.com/Lafriks
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'lv-LV',
+        cultureCode: 'lv-LV',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: ' tūkst.',
+            million: ' milj.',
+            billion: ' mljrd.',
+            trillion: ' trilj.'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language: Norwegian Bokmål
+ * locale: Norway
+ * author : Benjamin Van Ryseghem
+ */
+(function() {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'nb-NO',
+        cultureCode: 'nb-NO',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 't',
+            million: 'M',
+            billion: 'md',
+            trillion: 't'
+        },
+        currency: {
+            symbol: 'kr',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Dutch
+ * locale: Belgium
+ * author : Dieter Luypaert : https://github.com/moeriki
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'nl-BE',
+        cultureCode: 'nl-BE',
+        delimiters: {
+            thousands: ' ',
+            decimal  : ','
+        },
+        abbreviations: {
+            thousand : 'k',
+            million  : 'mln',
+            billion  : 'mld',
+            trillion : 'bln'
+        },
+        ordinal : function (number) {
+            var remainder = number % 100;
+            return (number !== 0 && remainder <= 1 || remainder === 8 || remainder >= 20) ? 'ste' : 'de';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Dutch
+ * locale: Netherlands
+ * author : Dave Clayton : https://github.com/davedx
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'nl-NL',
+        cultureCode: 'nl-NL',
+        delimiters: {
+            thousands: '.',
+            decimal  : ','
+        },
+        abbreviations: {
+            thousand : 'k',
+            million  : 'mln',
+            billion  : 'mrd',
+            trillion : 'bln'
+        },
+        ordinal : function (number) {
+            var remainder = number % 100;
+            return (number !== 0 && remainder <= 1 || remainder === 8 || remainder >= 20) ? 'ste' : 'de';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Polish
+ * locale : Poland
+ * author : Dominik Bulaj : https://github.com/dominikbulaj
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'pl-PL',
+        cultureCode: 'pl-PL',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'tys.',
+            million: 'mln',
+            billion: 'mld',
+            trillion: 'bln'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: ' zł',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Portuguese
+ * locale : Brazil
+ * author : Ramiro Varandas Jr : https://github.com/ramirovjr
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'pt-BR',
+        cultureCode: 'pt-BR',
+        delimiters: {
+            thousands: '.',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'mil',
+            million: 'milhões',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            return 'º';
+        },
+        currency: {
+            symbol: 'R$',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Portuguese
+ * locale : Portugal
+ * author : Diogo Resende : https://github.com/dresende
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'pt-PT',
+        cultureCode: 'pt-PT',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'k',
+            million: 'm',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal : function () {
+            return 'º';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Russian
+ * locale : Russsia
+ * author : Anatoli Papirovski : https://github.com/apapirovski
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'ru-RU',
+        cultureCode: 'ru-RU',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'тыс.',
+            million: 'млн',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            // not ideal, but since in Russian it can taken on
+            // different forms (masculine, feminine, neuter)
+            // this is all we can do
+            return '.';
+        },
+        currency: {
+            symbol: 'руб.',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Russian
+ * locale : Ukraine
+ * author : Anatoli Papirovski : https://github.com/apapirovski
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'ru-UA',
+        cultureCode: 'ru-UA',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'тыс.',
+            million: 'млн',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            // not ideal, but since in Russian it can taken on
+            // different forms (masculine, feminine, neuter)
+            // this is all we can do
+            return '.';
+        },
+        currency: {
+            symbol: '\u20B4',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Slovak
+ * locale : Slovakia
+ * author : Ahmed Al Hafoudh : http://www.freevision.sk
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'sk-SK',
+        cultureCode: 'sk-SK',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'tis.',
+            million: 'mil.',
+            billion: 'b',
+            trillion: 't'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '€',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Swedish
+ * locale : Sweden
+ * author : Benjamin Van Ryseghem (benjamin.vanryseghem.com)
+ */
+(function() {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'sv-SE',
+        cultureCode: 'sv-SE',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 't',
+            million: 'M',
+            billion: 'md',
+            trillion: 'tmd'
+        },
+        currency: {
+            symbol: 'kr',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Thai
+ * locale : Thailand
+ * author : Sathit Jittanupat : https://github.com/jojosati
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'th-TH',
+        cultureCode: 'th-TH',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: 'พัน',
+            million: 'ล้าน',
+            billion: 'พันล้าน',
+            trillion: 'ล้านล้าน'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '฿',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Turkish
+ * locale : Turkey
+ * author : Ecmel Ercan : https://github.com/ecmel,
+ *          Erhan Gundogan : https://github.com/erhangundogan,
+ *          Burak Yiğit Kaya: https://github.com/BYK
+ */
+(function() {
+    'use strict';
+
+    var suffixes = {
+            1: '\'inci',
+            5: '\'inci',
+            8: '\'inci',
+            70: '\'inci',
+            80: '\'inci',
+
+            2: '\'nci',
+            7: '\'nci',
+            20: '\'nci',
+            50: '\'nci',
+
+            3: '\'üncü',
+            4: '\'üncü',
+            100: '\'üncü',
+
+            6: '\'ncı',
+
+            9: '\'uncu',
+            10: '\'uncu',
+            30: '\'uncu',
+
+            60: '\'ıncı',
+            90: '\'ıncı'
+        },
+        language = {
+            langLocaleCode: 'tr-TR',
+            cultureCode: 'tr-TR',
+            delimiters: {
+                thousands: '.',
+                decimal: ','
+            },
+            abbreviations: {
+                thousand: 'bin',
+                million: 'milyon',
+                billion: 'milyar',
+                trillion: 'trilyon'
+            },
+            ordinal: function(number) {
+                if (number === 0) {  // special case for zero
+                    return '\'ıncı';
+                }
+
+                var a = number % 10,
+                    b = number % 100 - a,
+                    c = number >= 100 ? 100 : null;
+
+                return suffixes[a] || suffixes[b] || suffixes[c];
+            },
+            currency: {
+                symbol: '\u20BA',
+                position: 'postfix'
+            },
+            defaults: {
+                currencyFormat: ',4 a'
+            },
+            formats: {
+                fourDigits: '4 a',
+                fullWithTwoDecimals: ',0.00 $',
+                fullWithTwoDecimalsNoCurrency: ',0.00',
+                fullWithNoDecimals: ',0 $'
+            }
+        };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Ukrainian
+ * locale : Ukraine
+ * author : Michael Piefel : https://github.com/piefel (with help from Tetyana Kuzmenko)
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'uk-UA',
+        cultureCode: 'uk-UA',
+        delimiters: {
+            thousands: ' ',
+            decimal: ','
+        },
+        abbreviations: {
+            thousand: 'тис.',
+            million: 'млн',
+            billion: 'млрд',
+            trillion: 'блн'
+        },
+        ordinal: function () {
+            // not ideal, but since in Ukrainian it can taken on
+            // different forms (masculine, feminine, neuter)
+            // this is all we can do
+            return '';
+        },
+        currency: {
+            symbol: '\u20B4',
+            position: 'postfix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: ',0.00 $',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: ',0 $'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : simplified chinese
+ * locale : China
+ * author : badplum : https://github.com/badplum
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'zh-CN',
+        cultureCode: 'zh-CN',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: '千',
+            million: '百万',
+            billion: '十亿',
+            trillion: '兆'
+        },
+        ordinal: function () {
+            return '.';
+        },
+        currency: {
+            symbol: '¥',
+            position: 'prefix'
+        },
+        defaults: {
+            currencyFormat: ',4 a'
+        },
+        formats: {
+            fourDigits: '4 a',
+            fullWithTwoDecimals: '$ ,0.00',
+            fullWithTwoDecimalsNoCurrency: ',0.00',
+            fullWithNoDecimals: '$ ,0'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
+
+/*!
+ * numbro.js language configuration
+ * language : Chinese (Taiwan)
+ * author (numbro.js Version): Randy Wilander : https://github.com/rocketedaway
+ * author (numeral.js Version) : Rich Daley : https://github.com/pedantic-git
+ */
+(function () {
+    'use strict';
+
+    var language = {
+        langLocaleCode: 'zh-TW',
+        cultureCode: 'zh-TW',
+        delimiters: {
+            thousands: ',',
+            decimal: '.'
+        },
+        abbreviations: {
+            thousand: '千',
+            million: '百萬',
+            billion: '十億',
+            trillion: '兆'
+        },
+        ordinal: function () {
+            return '第';
+        },
+        currency: {
+            symbol: 'NT$'
+        }
+    };
+
+    // CommonJS
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = language;
+    }
+    // Browser
+    if (typeof window !== 'undefined' && window.numbro && window.numbro.culture) {
+        window.numbro.culture(language.cultureCode, language);
+    }
+}.call(typeof window === 'undefined' ? this : window));
diff --git a/inst/htmlwidgets/lib/sparkline/jquery.sparkline.min.js b/inst/htmlwidgets/lib/sparkline/jquery.sparkline.min.js
new file mode 100644
index 0000000..b39f5e5
--- /dev/null
+++ b/inst/htmlwidgets/lib/sparkline/jquery.sparkline.min.js
@@ -0,0 +1,4 @@
+/* jquery.sparkline 2.1.3 - http://omnipotent.net/jquery.sparkline/ 
+ Licensed under the New BSD License - see above site for details */
+!function(a,b,c){!function(a){"function"==typeof define&&define.amd?define("jquery.sparkline",["jquery"],a):jQuery&&!jQuery.fn.sparkline&&a(jQuery)}(function(d){"use strict";var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N={},O=0;e=function(){return{common:{type:"line",lineColor:"#00f",fillColor:"#cdf",defaultPixelsPerValue:3,width:"auto",height:"auto",composite:!1,tagValuesAttribute:"values",tagOptionsPrefix:"spark",enableTagOptions:!1,enableHighlight:!0,highl [...]
+f=j.get("thresholdColor")&&e<j.get("thresholdValue")?j.get("thresholdColor"):j.get("lineColor"),c&&(f=this.calcHighlightColor(f,j)),o.drawLine(g,d,g,d+q,f)}}),d.fn.sparkline.bullet=B=f(d.fn.sparkline._base,{type:"bullet",init:function(a,d,e,f,g){var h,i,j;B._super.init.call(this,a,d,e,f,g),this.values=d=l(d),j=d.slice(),j[0]=null===j[0]?j[2]:j[0],j[1]=null===d[1]?j[2]:j[1],h=b.min.apply(b,d),i=b.max.apply(b,d),h=e.get("base")===c?h<0?h:0:e.get("base"),this.min=h,this.max=i,this.range=i-h [...]
\ No newline at end of file
diff --git a/inst/htmlwidgets/rhandsontable.css b/inst/htmlwidgets/rhandsontable.css
new file mode 100644
index 0000000..b6ac0d9
--- /dev/null
+++ b/inst/htmlwidgets/rhandsontable.css
@@ -0,0 +1,27 @@
+.handsontable .currentRow {
+  background-color: #E7E8EF;
+}
+
+.handsontable .currentCol {
+  background-color: #F9F9FB;
+}
+
+.handsontable {
+  overflow: auto;
+}
+
+/* fix for sparkline hover */
+.jqstooltip{
+  width: auto !important;
+  height: auto !important;
+}
+
+/* fix for shiny datepicker */
+.datepicker {
+  z-index: 1000 !important;
+}
+
+.handsontable table thead th {
+  white-space: pre-line;
+  /*max-width: /* enter here your max header width */
+}
diff --git a/inst/htmlwidgets/rhandsontable.js b/inst/htmlwidgets/rhandsontable.js
new file mode 100644
index 0000000..cf8b8d8
--- /dev/null
+++ b/inst/htmlwidgets/rhandsontable.js
@@ -0,0 +1,412 @@
+HTMLWidgets.widget({
+
+  name: 'rhandsontable',
+
+  type: 'output',
+
+  params: null,
+
+  initialize: function(el, width, height) {
+
+    return {
+
+    };
+
+  },
+
+  renderValue: function(el, x, instance) {
+
+    // convert json to array
+    if (x.data.length > 0 && x.data[0].constructor === Array) {
+      x.data = x.data;
+    } else {
+      x.data = toArray(x.data.map(function(d) {
+        return x.rColnames.map(function(ky) {
+          return d[ky];
+        });
+      }));
+    }
+
+    if (x.isHeatmap === true) {
+      x.afterLoadData = this.initHeatmap;
+      x.beforeChangeRender = this.updateHeatmap;
+    }
+
+    if (x.overflow) {
+      $("#" + el.id).css('overflow', x.overflow);
+    }
+
+    if (x.rowHeaderWidth) {
+      $("#" + el.id).css('col.rowHeader', x.rowHeaderWidth + 'px');
+    }
+
+    //this.afterRender(x);
+
+    this.params = x;
+
+    if (instance.hot) { // update existing instance
+      if (x.debug && x.debug > 0) {
+        console.log("rhandsontable: update table");
+      }
+
+      instance.hot.params = x;
+      instance.hot.updateSettings(x);
+    } else {  // create new instance
+      if (x.debug && x.debug > 0) {
+        console.log("rhandsontable: new table");
+      }
+
+      instance.hot = new Handsontable(el, x);
+
+      this.afterChangeCallback(x);
+      this.afterCellMetaCallback(x);
+      this.afterRowAndColChange(x);
+
+      if (x.selectCallback) {
+        this.afterSelectCallback(x);
+      }
+
+      instance.hot.params = x;
+      instance.hot.updateSettings(x);
+    }
+  },
+
+  resize: function(el, width, height, instance) {
+
+  },
+
+  afterRender: function(x) {
+    x.afterRender = function(isForced) {
+      var plugin = this.getPlugin('autoColumnSize');
+      if (plugin.isEnabled() && this.params) {
+        if (this.params && this.params.debug) {
+          if (this.params.debug > 0) {
+            console.log("rhandsontable: resizing column widths");
+          }
+        }
+
+        var wdths = plugin.widths;
+        for(var i = 0, colCount = this.countCols(); i < colCount ; i++) {
+          if (this.params.columns && this.params.columns[i].renderer.name != "customRenderer") {
+            plugin.calculateColumnsWidth(i, 300, true);
+          }
+        }
+      }
+    };
+  },
+
+  afterChangeCallback: function(x) {
+
+    x.afterChange = function(changes, source) {
+      if (this.params && this.params.debug) {
+        if (this.params.debug > 0) {
+          console.log("afterChange: " + source);
+        }
+        if (this.params.debug > 1) {
+          console.log("afterChange:");
+          console.log(changes);
+        }
+      }
+
+      if (HTMLWidgets.shinyMode) {
+        if (changes && changes[0][2] !== null && changes[0][3] !== null) {
+          if (this.sortIndex && this.sortIndex.length !== 0) {
+            c = [this.sortIndex[changes[0][0]][0], changes[0].slice(1, 1 + 3)];
+          } else {
+            c = changes;
+          }
+
+          if (this.params && this.params.debug) {
+            if (this.params.debug > 0) {
+              console.log("afterChange: Shiny.onInputChange: " + this.rootElement.id);
+            }
+          }
+          Shiny.onInputChange(this.rootElement.id, {
+            data: this.getData(),
+            changes: { event: "afterChange", changes: c, source: source },
+            params: this.params
+          });
+        } else if (source == "loadData" && this.params) {
+
+          if (this.params && this.params.debug) {
+            if (this.params.debug > 0) {
+              console.log("afterChange: Shiny.onInputChange: " + this.rootElement.id);
+            }
+          }
+          Shiny.onInputChange(this.rootElement.id, {
+            data: this.getData(),
+            changes: { event: "afterChange", changes: null },
+            params: this.params
+          });
+        }
+      }
+
+    };
+
+    x.afterLoadData = function(firstTime) {
+      if (this.params && this.params.debug) {
+        if (this.params.debug > 0) {
+          console.log("afterLoadData: " + firstTime);
+        }
+      }
+    };
+
+    x.afterChangesObserved = function(firstTime) {
+      if (this.params && this.params.debug) {
+        if (this.params.debug > 0) {
+          console.log("afterChangesObserved");
+        }
+      }
+    };
+
+    x.afterInit = function() {
+      if (this.params && this.params.debug) {
+        if (this.params.debug > 0) {
+          console.log("afterInit");
+        }
+      }
+    };
+  },
+
+  afterCellMetaCallback: function(x) {
+
+    x.afterSetCellMeta = function(r, c, key, val) {
+
+      if (HTMLWidgets.shinyMode && key === "comment") {
+        if (this.sortIndex && this.sortIndex.length !== 0) {
+          r = this.sortIndex[r][0];
+        }
+
+        if (this.params && this.params.debug) {
+          if (this.params.debug > 0) {
+            console.log("afterSetCellMeta: Shiny.onInputChange: " + this.rootElement.id);
+          }
+        }
+        Shiny.onInputChange(this.rootElement.id + "_comment", {
+          data: this.getData(),
+          comment: { r: r + 1, c: c + 1, key: key, val: val},
+          params: this.params
+        });
+      }
+
+    };
+  },
+
+  afterSelectCallback: function(x) {
+
+    x.afterSelectionEnd = function(r, c, r2, c2) {
+
+      if (HTMLWidgets.shinyMode) {
+        if (this.sortIndex && this.sortIndex.length !== 0) {
+          r = this.sortIndex[r][0];
+          r2 = this.sortIndex[r2][0];
+        }
+
+        if (this.params && this.params.debug) {
+          if (this.params.debug > 0) {
+            console.log("afterSelectionEnd: Shiny.onInputChange: " + this.rootElement.id);
+          }
+        }
+        Shiny.onInputChange(this.rootElement.id + "_select", {
+          data: this.getData(),
+          select: { r: r + 1, c: c + 1, r2: r2 + 1, c2: c2 + 1},
+          params: this.params
+        });
+      }
+
+    };
+  },
+
+  afterRowAndColChange: function(x) {
+
+    x.afterCreateRow = function(ind, ct) {
+
+      if (HTMLWidgets.shinyMode) {
+
+        for(var i = 0, colCount = this.countCols(); i < colCount ; i++) {
+          this.setDataAtCell(ind, i, this.params.columns[i].default);
+        }
+
+        if (this.params && this.params.debug) {
+          if (this.params.debug > 0) {
+            console.log("afterCreateRow: Shiny.onInputChange: " + this.rootElement.id);
+          }
+        }
+        Shiny.onInputChange(this.rootElement.id, {
+          data: this.getData(),
+          changes: { event: "afterCreateRow", ind: ind, ct: ct },
+          params: this.params
+        });
+      }
+    };
+
+    x.afterRemoveRow = function(ind, ct) {
+
+      if (HTMLWidgets.shinyMode)
+        if (this.params && this.params.debug) {
+          if (this.params.debug > 0) {
+            console.log("afterRemoveRow: Shiny.onInputChange: " + this.rootElement.id);
+          }
+        }
+        Shiny.onInputChange(this.rootElement.id, {
+          data: this.getData(),
+          changes: { event: "afterRemoveRow", ind: ind, ct: ct },
+          params: this.params
+        });
+    };
+
+    x.afterCreateCol = function(ind, ct) {
+
+      if (HTMLWidgets.shinyMode)
+        if (this.params && this.params.debug) {
+          if (this.params.debug > 0) {
+            console.log("afterCreateCol: Shiny.onInputChange: " + this.rootElement.id);
+          }
+        }
+        Shiny.onInputChange(this.rootElement.id, {
+          data: this.getData(),
+          changes: { event: "afterCreateCol", ind: ind, ct: ct },
+          params: this.params
+        });
+    };
+
+    x.afterRemoveCol = function(ind, ct) {
+
+      if (HTMLWidgets.shinyMode)
+        if (this.params && this.params.debug) {
+          if (this.params.debug > 0) {
+            console.log("afterRemoveCol: Shiny.onInputChange: " + this.rootElement.id);
+          }
+        }
+        Shiny.onInputChange(this.rootElement.id, {
+          data: this.getData(),
+          changes: { event: "afterRemoveCol", ind: ind, ct: ct },
+          params: this.params
+        });
+    };
+
+  },
+
+  // see http://handsontable.com/demo/heatmaps.html
+  initHeatmap: function(firstTime, source) {
+    this.heatmap = [];
+
+    for(var i = 0, colCount = this.countCols(); i < colCount ; i++) {
+      this.heatmap[i] = generateHeatmapData.call(this, i);
+    }
+  },
+
+  updateHeatmap: function(change, source) {
+    this.heatmap[change[0][1]] = generateHeatmapData.call(this, change[0][1]);
+  }
+
+});
+
+function generateHeatmapData(colId) {
+
+  var values = this.getDataAtCol(colId);
+
+  return {
+    min: Math.min.apply(null, values),
+    max: Math.max.apply(null, values)
+  };
+}
+
+// https://stackoverflow.com/questions/22477612/converting-array-of-objects-into-array-of-arrays
+function toArray(input) {
+  var result = input.map(function(obj) {
+    return Object.keys(obj).map(function(key) {
+      return obj[key];
+    });
+  });
+  return result;
+}
+
+// csv logic adapted from https://github.com/juantascon/jquery-handsontable-csv
+function csvString(instance) {
+
+  var headers = instance.getColHeader();
+
+  var csv = headers.join(",") + "\n";
+
+  for (var i = 0; i < instance.countRows(); i++) {
+      var row = [];
+      for (var h in headers) {
+          var col = instance.propToCol(h);
+          var value = instance.getDataAtRowProp(i, col);
+          row.push(value);
+      }
+
+      csv += row.join(",");
+      csv += "\n";
+  }
+
+  return csv;
+}
+
+function customRenderer(instance, TD, row, col, prop, value, cellProperties) {
+  if (value === 'NA') {
+    value = '';
+    Handsontable.renderers.getRenderer('text')(instance, TD, row, col, prop, value, cellProperties);
+  } else {
+    if (['date', 'handsontable', 'dropdown'].indexOf(cellProperties.type) > -1) {
+      type = 'autocomplete';
+    } else {
+      type = cellProperties.type;
+    }
+    Handsontable.renderers.getRenderer(type)(instance, TD, row, col, prop, value, cellProperties);
+  }
+}
+
+function renderSparkline(instance, td, row, col, prop, value, cellProperties) {
+  try {
+    val = JSON.parse(value);
+
+    nm = 'sparklines_r' + row + '_c' + col;
+    td.innerHTML = '<span class=\"' + nm + '\"></span>';
+
+    // adjust for cell padding
+    if (val.options && val.options.type &&
+      ['bar', 'tristate'].indexOf(val.options.type[0]) > -1) {
+      val.options.barSpacing = 1;
+      val.options.barWidth = Math.max(1, Math.round((instance.getColWidth(col) - 8 - (val.values.length - 1)) / val.values.length));
+    } else {
+      if (!val.options) {
+        val.options = {};
+      }
+      val.options.width = (instance.getColWidth(col) - 8) + "px";
+    }
+
+    $('.' + nm).sparkline(val.values, val.options);
+  } catch(err) {
+    td.innerHTML = '';
+  }
+
+  return td;
+}
+
+// http://docs.handsontable.com/0.16.1/demo-custom-renderers.html
+function strip_tags(input, allowed) {
+  var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
+    commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
+
+  // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
+  allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('');
+
+  return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
+    return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
+  });
+}
+
+function safeHtmlRenderer(instance, td, row, col, prop, value, cellProperties) {
+  var escaped = Handsontable.helper.stringify(value);
+  if (instance.getSettings().allowedTags) {
+    tags = instance.getSettings().allowedTags;
+  } else {
+    tags = '<em><b><strong><a><big>';
+  }
+  escaped = strip_tags(escaped, tags); //be sure you only allow certain HTML tags to avoid XSS threats (you should also remove unwanted HTML attributes)
+  td.innerHTML = escaped;
+
+  return td;
+}
diff --git a/inst/htmlwidgets/rhandsontable.yaml b/inst/htmlwidgets/rhandsontable.yaml
new file mode 100644
index 0000000..ff6673d
--- /dev/null
+++ b/inst/htmlwidgets/rhandsontable.yaml
@@ -0,0 +1,27 @@
+# (uncomment to add a dependency)
+dependencies:
+ - name: handsontable
+   version: 0.28.4
+   src: "htmlwidgets/lib/handsontable"
+   script: handsontable.full.min.js
+   stylesheet: handsontable.full.min.css
+ - name: numbro.languages
+   version: 1.9.2
+   src: "htmlwidgets/lib/numbro"
+   script: languages.js
+ - name: chroma
+   version: 1.1.0
+   src: "htmlwidgets/lib/chroma"
+   script: chroma.min.js
+ - name: jquery
+   version: 2.2.1
+   src: "htmlwidgets/lib/jquery"
+   script: jquery.min.js
+ - name: sparkline
+   version: 2.1.2
+   src: "htmlwidgets/lib/sparkline"
+   script: jquery.sparkline.min.js
+ - name: rhandsontable
+   version: 0.3.4
+   src: "htmlwidgets"
+   stylesheet: rhandsontable.css
diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf
new file mode 100644
index 0000000..7d73329
--- /dev/null
+++ b/inst/rstudio/addins.dcf
@@ -0,0 +1,4 @@
+Name: Edit a Data Frame
+Description: Interactively edit a data frame.
+Binding: editAddin
+Interactive: true
diff --git a/man/editAddin.Rd b/man/editAddin.Rd
new file mode 100644
index 0000000..bfd2f4a
--- /dev/null
+++ b/man/editAddin.Rd
@@ -0,0 +1,26 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/editAddin.R
+\name{editAddin}
+\alias{editAddin}
+\title{Edit a Data Frame.}
+\usage{
+editAddin()
+}
+\description{
+Interactively edit a \code{data.frame} or \code{data.table}. The resulting
+code will be emitted as a call to reload the data from a temp RDS file.
+}
+\details{
+This addin can be used to interactively edit.
+The intended way to use this is as follows:
+
+1. Highlight a symbol naming a \code{data.frame} or \code{data.table}
+   in your R session, e.g. \code{mtcars}.
+2. Execute this addin, to interactively edit it.
+
+When you're done, the code performing this operation will be emitted
+at the cursor position.
+
+This function borrows heavily from \href{rstudio/addinexamples/subsetAddin}{https://github.com/rstudio/addinexamples/blob/master/R/subsetAddin.R}
+}
+
diff --git a/man/hot_cell.Rd b/man/hot_cell.Rd
new file mode 100644
index 0000000..3a0d5a8
--- /dev/null
+++ b/man/hot_cell.Rd
@@ -0,0 +1,35 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_cell}
+\alias{hot_cell}
+\title{Handsontable widget}
+\usage{
+hot_cell(hot, row, col, comment = NULL)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{row}{numeric row index}
+
+\item{col}{numeric column index}
+
+\item{comment}{character comment to add to cell}
+}
+\description{
+Configure single cell.  See
+\href{http://handsontable.com}{Handsontable.js} for details.
+}
+\examples{
+library(rhandsontable)
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, readOnly = TRUE) \%>\%
+  hot_cell(1, 1, "Test comment")
+}
+\seealso{
+\code{\link{hot_cols}}, \code{\link{hot_rows}}
+}
+
diff --git a/man/hot_col.Rd b/man/hot_col.Rd
new file mode 100644
index 0000000..793a3a9
--- /dev/null
+++ b/man/hot_col.Rd
@@ -0,0 +1,81 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_col}
+\alias{hot_col}
+\title{Handsontable widget}
+\usage{
+hot_col(hot, col, type = NULL, format = NULL, source = NULL,
+  strict = NULL, readOnly = NULL, validator = NULL, allowInvalid = NULL,
+  halign = NULL, valign = NULL, renderer = NULL, copyable = NULL,
+  dateFormat = NULL, default = NULL, language = NULL, ...)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{col}{vector of column names or indices}
+
+\item{type}{character specify the data type. Options include:
+numeric, date, checkbox, select, dropdown, autocomplete, password,
+and handsontable (not implemented yet)}
+
+\item{format}{characer specifying column format. See Cell Types at
+\href{http://handsontable.com}{Handsontable.js} for the formatting
+options for each data type. Numeric columns are formatted using
+\href{http://numeraljs.com}{Numeral.js}.}
+
+\item{source}{a vector of choices for select, dropdown and autocomplete
+column types}
+
+\item{strict}{logical specifying whether values not in the \code{source}
+vector will be accepted}
+
+\item{readOnly}{logical making the table read-only}
+
+\item{validator}{character defining a Javascript function to be used
+to validate user input. See \code{hot_validate_numeric} and
+\code{hot_validate_character} for pre-build validators.}
+
+\item{allowInvalid}{logical specifying whether invalid data will be
+accepted. Invalid data cells will be color red.}
+
+\item{halign}{character defining the horizontal alignment. Possible
+values are htLeft, htCenter, htRight and htJustify}
+
+\item{valign}{character defining the vertical alignment. Possible
+values are htTop, htMiddle, htBottom}
+
+\item{renderer}{character defining a Javascript function to be used
+to format column cells. Can be used to implement conditional formatting.}
+
+\item{copyable}{logical defining whether data in a cell can be copied using
+Ctrl + C}
+
+\item{dateFormat}{character defining the date format. See
+\href{https://github.com/moment/moment}{Moment.js} for details.}
+
+\item{default}{default column value for new rows (NA if not specified; shiny only)}
+
+\item{language}{locale passed to \href{http://numbrojs.com}{Numbro.js};
+default is 'en-US'.}
+
+\item{...}{passed to handsontable}
+}
+\description{
+Configure single column.
+}
+\examples{
+library(rhandsontable)
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, rowHeaders = NULL) \%>\%
+  hot_col(col = "big", type = "dropdown", source = LETTERS) \%>\%
+  hot_col(col = "small", type = "autocomplete", source = letters,
+          strict = FALSE)
+}
+\seealso{
+\code{\link{hot_cols}}, \code{\link{hot_rows}}, \code{\link{hot_cell}}
+}
+
diff --git a/man/hot_cols.Rd b/man/hot_cols.Rd
new file mode 100644
index 0000000..0a17212
--- /dev/null
+++ b/man/hot_cols.Rd
@@ -0,0 +1,45 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_cols}
+\alias{hot_cols}
+\title{Handsontable widget}
+\usage{
+hot_cols(hot, colWidths = NULL, columnSorting = NULL,
+  manualColumnMove = NULL, manualColumnResize = NULL,
+  fixedColumnsLeft = NULL, ...)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{colWidths}{a scalar or numeric vector of column widths}
+
+\item{columnSorting}{logical enabling row sorting. Sorting only alters the
+table presentation and the original dataset row order is maintained.
+The sorting will be done when a user click on column name}
+
+\item{manualColumnMove}{logical enabling column drag-and-drop reordering}
+
+\item{manualColumnResize}{logical enabline column width resizing}
+
+\item{fixedColumnsLeft}{a numeric vector indicating which columns should be
+frozen on the left}
+
+\item{...}{passed to hot_col}
+}
+\description{
+Configure multiple columns.
+}
+\examples{
+library(rhandsontable)
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF) \%>\%
+  hot_cols(columnSorting = TRUE)
+}
+\seealso{
+\code{\link{hot_col}}, \code{\link{hot_rows}}, \code{\link{hot_cell}}
+}
+
diff --git a/man/hot_context_menu.Rd b/man/hot_context_menu.Rd
new file mode 100644
index 0000000..82ac66a
--- /dev/null
+++ b/man/hot_context_menu.Rd
@@ -0,0 +1,46 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_context_menu}
+\alias{hot_context_menu}
+\title{Handsontable widget}
+\usage{
+hot_context_menu(hot, allowRowEdit = TRUE, allowColEdit = TRUE,
+  allowReadOnly = FALSE, allowComments = FALSE,
+  allowCustomBorders = FALSE, customOpts = NULL, ...)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{allowRowEdit}{logical enabling row editing}
+
+\item{allowColEdit}{logical enabling column editing. Note that
+Handsontable does not support column add/remove when column types
+are defined (i.e. useTypes == TRUE in rhandsontable).}
+
+\item{allowReadOnly}{logical enabling read-only toggle}
+
+\item{allowComments}{logical enabling comments}
+
+\item{allowCustomBorders}{logical enabling custom borders}
+
+\item{customOpts}{list}
+
+\item{...}{ignored}
+}
+\description{
+Configure the options for the right-click context menu.  See
+ \href{http://docs.handsontable.com/0.16.1/demo-context-menu.html}{Context Menu} and
+ \href{http://swisnl.github.io/jQuery-contextMenu/docs.html}{jquery contextMenu}
+ for details.
+}
+\examples{
+library(rhandsontable)
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF) \%>\%
+  hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE)
+}
+
diff --git a/man/hot_heatmap.Rd b/man/hot_heatmap.Rd
new file mode 100644
index 0000000..abc5db4
--- /dev/null
+++ b/man/hot_heatmap.Rd
@@ -0,0 +1,35 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_heatmap}
+\alias{hot_heatmap}
+\title{Handsontable widget}
+\usage{
+hot_heatmap(hot, cols, color_scale = c("#ED6D47", "#17F556"),
+  renderer = NULL)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{cols}{numeric vector of columns to include in the heatmap. If missing
+all columns are used.}
+
+\item{color_scale}{character vector that includes the lower and upper
+colors}
+
+\item{renderer}{character defining a Javascript function to be used
+to determine the cell colors. If missing,
+\code{rhandsontable:::renderer_heatmap} is used.}
+}
+\description{
+Add heatmap to table.  See
+\href{http://docs.handsontable.com/0.16.1/demo-chromajs.html}{Heatmaps for values in a column}
+for details.
+}
+\examples{
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+             letters[1:5]))
+
+rhandsontable(MAT) \%>\%
+ hot_heatmap()
+}
+
diff --git a/man/hot_rows.Rd b/man/hot_rows.Rd
new file mode 100644
index 0000000..c66a3bd
--- /dev/null
+++ b/man/hot_rows.Rd
@@ -0,0 +1,33 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_rows}
+\alias{hot_rows}
+\title{Handsontable widget}
+\usage{
+hot_rows(hot, rowHeights = NULL, fixedRowsTop = NULL)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{rowHeights}{a scalar or numeric vector of row heights}
+
+\item{fixedRowsTop}{a numeric vector indicating which rows should be
+frozen on the top}
+}
+\description{
+Configure rows.  See
+\href{http://handsontable.com}{Handsontable.js} for details.
+}
+\examples{
+library(rhandsontable)
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+             letters[1:5]))
+
+rhandsontable(MAT, width = 300, height = 150) \%>\%
+hot_cols(colWidths = 100, fixedColumnsLeft = 1) \%>\%
+  hot_rows(rowHeights = 50, fixedRowsTop = 1)
+}
+\seealso{
+\code{\link{hot_cols}}, \code{\link{hot_cell}}
+}
+
diff --git a/man/hot_table.Rd b/man/hot_table.Rd
new file mode 100644
index 0000000..24fb24b
--- /dev/null
+++ b/man/hot_table.Rd
@@ -0,0 +1,54 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_table}
+\alias{hot_table}
+\title{Handsontable widget}
+\usage{
+hot_table(hot, contextMenu = TRUE, stretchH = "none",
+  customBorders = NULL, highlightRow = NULL, highlightCol = NULL,
+  enableComments = FALSE, overflow = NULL, rowHeaderWidth = NULL, ...)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{contextMenu}{logical enabling the right-click menu}
+
+\item{stretchH}{character describing column stretching. Options are 'all', 'right',
+and 'none'. See \href{http://docs.handsontable.com/0.16.1/demo-stretching.html}{Column stretching} for details.}
+
+\item{customBorders}{json object. See
+\href{http://handsontable.com/demo/custom_borders.html}{Custom borders} for details.}
+
+\item{highlightRow}{logical enabling row highlighting for the selected
+cell}
+
+\item{highlightCol}{logical enabling column highlighting for the
+selected cell}
+
+\item{enableComments}{logical enabling comments in the table}
+
+\item{overflow}{character setting the css overflow behavior. Options are
+auto (default), hidden and visible}
+
+\item{rowHeaderWidth}{numeric width (in px) for the rowHeader column}
+
+\item{...}{passed to \href{http://handsontable.com}{Handsontable.js} constructor}
+}
+\description{
+Configure table.  See
+\href{http://handsontable.com}{Handsontable.js} for details.
+}
+\examples{
+library(rhandsontable)
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF) \%>\%
+hot_table(highlightCol = TRUE, highlightRow = TRUE)
+}
+\seealso{
+\code{\link{rhandsontable}}
+}
+
diff --git a/man/hot_to_r.Rd b/man/hot_to_r.Rd
new file mode 100644
index 0000000..b227a36
--- /dev/null
+++ b/man/hot_to_r.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_to_r}
+\alias{hot_to_r}
+\title{Handsontable widget}
+\usage{
+hot_to_r(...)
+}
+\arguments{
+\item{...}{passed to \code{rhandsontable:::toR}}
+}
+\description{
+Convert handsontable data to R object. Can be used in a \code{shiny} app
+ to convert the input json to an R dataset.
+}
+\seealso{
+\code{\link{rHandsontableOutput}}
+}
+
diff --git a/man/hot_validate_character.Rd b/man/hot_validate_character.Rd
new file mode 100644
index 0000000..66386f5
--- /dev/null
+++ b/man/hot_validate_character.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_validate_character}
+\alias{hot_validate_character}
+\title{Handsontable widget}
+\usage{
+hot_validate_character(hot, cols, choices, allowInvalid = FALSE)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{cols}{vector of column names or indices}
+
+\item{choices}{a vector of acceptable numeric choices. It will be evaluated
+after min and max if specified.}
+
+\item{allowInvalid}{logical specifying whether invalid data will be
+accepted. Invalid data cells will be color red.}
+}
+\description{
+Add numeric validation to a column
+}
+\examples{
+library(rhandsontable)
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF) \%>\%
+  hot_validate_character(col = "big", choices = LETTERS[1:10])
+}
+\seealso{
+\code{\link{hot_validate_numeric}}
+}
+
diff --git a/man/hot_validate_numeric.Rd b/man/hot_validate_numeric.Rd
new file mode 100644
index 0000000..1f9d159
--- /dev/null
+++ b/man/hot_validate_numeric.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{hot_validate_numeric}
+\alias{hot_validate_numeric}
+\title{Handsontable widget}
+\usage{
+hot_validate_numeric(hot, cols, min = NULL, max = NULL, choices = NULL,
+  exclude = NULL, allowInvalid = FALSE)
+}
+\arguments{
+\item{hot}{rhandsontable object}
+
+\item{cols}{vector of column names or indices}
+
+\item{min}{minimum value to accept}
+
+\item{max}{maximum value to accept}
+
+\item{choices}{a vector of acceptable numeric choices. It will be evaluated
+after min and max if specified.}
+
+\item{exclude}{a vector of unacceptable numeric values}
+
+\item{allowInvalid}{logical specifying whether invalid data will be
+accepted. Invalid data cells will be color red.}
+}
+\description{
+Add numeric validation to a column
+}
+\examples{
+library(rhandsontable)
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+             letters[1:5]))
+
+rhandsontable(MAT * 10) \%>\%
+  hot_validate_numeric(col = 1, min = -50, max = 50, exclude = 40)
+
+rhandsontable(MAT * 10) \%>\%
+  hot_validate_numeric(col = 1, choices = c(10, 20, 40))
+}
+\seealso{
+\code{\link{hot_validate_character}}
+}
+
diff --git a/man/rHandsontableOutput.Rd b/man/rHandsontableOutput.Rd
new file mode 100644
index 0000000..d4ec0ed
--- /dev/null
+++ b/man/rHandsontableOutput.Rd
@@ -0,0 +1,21 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{rHandsontableOutput}
+\alias{rHandsontableOutput}
+\title{Handsontable widget}
+\usage{
+rHandsontableOutput(outputId, width = "100\%", height = "100\%")
+}
+\arguments{
+\item{outputId}{output variable to read from}
+
+\item{width, height}{must be a valid CSS unit in pixels
+or a number, which will be coerced to a string and have \code{"px"} appended.}
+}
+\description{
+Shiny bindings for rhandsontable
+}
+\seealso{
+\code{\link{renderRHandsontable}}
+}
+
diff --git a/man/renderRHandsontable.Rd b/man/renderRHandsontable.Rd
new file mode 100644
index 0000000..1b9aa7c
--- /dev/null
+++ b/man/renderRHandsontable.Rd
@@ -0,0 +1,23 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{renderRHandsontable}
+\alias{renderRHandsontable}
+\title{Handsontable widget}
+\usage{
+renderRHandsontable(expr, env = parent.frame(), quoted = FALSE)
+}
+\arguments{
+\item{expr}{an expression that generates an rhandsontable.}
+
+\item{env}{the environment in which to evaluate \code{expr}.}
+
+\item{quoted}{is \code{expr} a quoted expression (with \code{quote()})? This
+is useful if you want to save an expression in a variable.}
+}
+\description{
+Shiny bindings for rhandsontable
+}
+\seealso{
+\code{\link{rHandsontableOutput}}, \code{\link{hot_to_r}}
+}
+
diff --git a/man/rhandsontable-exports.Rd b/man/rhandsontable-exports.Rd
new file mode 100644
index 0000000..c0bc110
--- /dev/null
+++ b/man/rhandsontable-exports.Rd
@@ -0,0 +1,12 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable-package.R
+\name{rhandsontable-exports}
+\alias{\%>\%}
+\alias{rhandsontable-exports}
+\title{rhandsontable exported operators}
+\description{
+The following functions are imported and then re-exported
+from the rhandsontable package to enable use of the magrittr
+pipe operator with no additional library calls
+}
+
diff --git a/man/rhandsontable-package.Rd b/man/rhandsontable-package.Rd
new file mode 100644
index 0000000..387d853
--- /dev/null
+++ b/man/rhandsontable-package.Rd
@@ -0,0 +1,13 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable-package.R
+\docType{package}
+\name{rhandsontable-package}
+\alias{rhandsontable-package}
+\title{rhandsontable}
+\description{
+R interface for creating tables using Handsontable, url{http://http://handsontable.com/}
+}
+\details{
+For full documentation on the package, visit \url{http://jrowen.github.io/rhandsontable/}
+}
+
diff --git a/man/rhandsontable.Rd b/man/rhandsontable.Rd
new file mode 100644
index 0000000..3de4f60
--- /dev/null
+++ b/man/rhandsontable.Rd
@@ -0,0 +1,60 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/rhandsontable.R
+\name{rhandsontable}
+\alias{rhandsontable}
+\title{Handsontable widget}
+\usage{
+rhandsontable(data, colHeaders, rowHeaders, comments = NULL,
+  useTypes = TRUE, readOnly = NULL, selectCallback = FALSE,
+  width = NULL, height = NULL, digits = 4, debug = NULL, ...)
+}
+\arguments{
+\item{data}{a \code{data.table}, \code{data.frame} or \code{matrix}}
+
+\item{colHeaders}{a vector of column names. If missing \code{colnames}
+will be used. Setting to \code{NULL} will omit.}
+
+\item{rowHeaders}{a vector of row names. If missing \code{rownames}
+will be used. Setting to \code{NULL} will omit.}
+
+\item{comments}{matrix or data.frame of comments; NA values are ignored}
+
+\item{useTypes}{logical specifying whether column classes should be mapped to
+equivalent Javascript types.  Note that
+Handsontable does not support column add/remove when column types
+are defined (i.e. useTypes == TRUE in rhandsontable).}
+
+\item{readOnly}{logical specifying whether the table is editable}
+
+\item{selectCallback}{logical enabling the afterSelect event to return data.
+This can be used with shiny to tie updates to a selected table cell.}
+
+\item{width}{numeric table width}
+
+\item{height}{numeric table height}
+
+\item{digits}{numeric passed to \code{jsonlite::toJSON}}
+
+\item{debug}{numeric Javascript log level}
+
+\item{...}{passed to \code{hot_table} and to the \code{params} property of the widget}
+}
+\description{
+Create a \href{http://handsontable.com}{Handsontable.js} widget.
+}
+\details{
+For full documentation on the package, visit \url{http://jrowen.github.io/rhandsontable/}
+}
+\examples{
+library(rhandsontable)
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, rowHeaders = NULL)
+}
+\seealso{
+\code{\link{hot_table}}, \code{\link{hot_cols}}, \code{\link{hot_rows}}, \code{\link{hot_cell}}
+}
+
diff --git a/vignettes/intro_rhandsontable.Rmd b/vignettes/intro_rhandsontable.Rmd
new file mode 100644
index 0000000..8040299
--- /dev/null
+++ b/vignettes/intro_rhandsontable.Rmd
@@ -0,0 +1,620 @@
+---
+title: "rhandsontable Introduction"
+author: "Jonathan Owen"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{rhandsontable Introduction}
+  %\VignetteEngine{knitr::rmarkdown}
+  \usepackage[utf8]{inputenc}
+---
+
+```{r echo = FALSE}
+library(rhandsontable)
+library(knitr)
+
+opts_knit$set(warning = FALSE, error = FALSE, message = FALSE, cache = FALSE,
+              fig.width=7, fig.height=3)
+```
+
+## Introduction
+
+  rhandsontable is a htmlwidget based on the [handsontable.js](https://www.handsontable.com) library.
+
+> Handsontable is a data grid component with an Excel-like appearance. Built in JavaScript, it integrates with any data source with peak efficiency. It comes with powerful features like data validation, sorting, grouping, data binding, formula support or column ordering.
+([via](https://www.handsontable.com))
+
+## Column Types
+
+The table includes support for numeric, logical, character and Date types.  Logical values will appear as check boxes, and the [pikaday.js](https://github.com/dbushell/Pikaday) library is used to specify Date values.
+
+rhandsontable attempts to map R classes to an appropriate handsontable type.  Factors will be mapped to `dropdown`, with the choices specified by `level` and `allowInvalid` set to `FALSE`.  To allow new levels, set `allowInvalid` to `TRUE` (using `hot_col`; it may also be desirable to set `strict` to `FALSE`).  When running in `shiny`, using `hot_to_r` will preserve custom factor ordering, and if new levels are allowed, they will be added to the end.
+
+```{r}
+DF = data.frame(integer = 1:10,
+                   numeric = rnorm(10),
+                   logical = rep(TRUE, 10), 
+                   character = LETTERS[1:10],
+                   factor = factor(letters[1:10], levels = letters[10:1], 
+                                   ordered = TRUE),
+                   factor_allow = factor(letters[1:10], levels = letters[10:1], 
+                                         ordered = TRUE),
+                   date = seq(from = Sys.Date(), by = "days", length.out = 10),
+                   stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 600, height = 300) %>%
+  hot_col("factor_allow", allowInvalid = TRUE)
+```
+
+To improve readability, `NA` values will be displayed as blank cells.  This requires converting columns containing `NA` to characters, and in the case of factors and Dates, may not display the data in the desired format.  It may be beneficial to concert these type of columns to character before passing to `rhandsontable`.
+
+```{r}
+DF_na = data.frame(integer = c(NA, 2:10), 
+                   logical = c(NA, rep(TRUE, 9)), 
+                   character = c(NA, LETTERS[1:9]),
+                   factor = c(NA, factor(letters[1:9])),
+                   date = c(NA, seq(from = Sys.Date(), by = "days", 
+                                    length.out = 9)),
+                   stringsAsFactors = FALSE)
+
+DF_na$factor_ch = as.character(DF_na$factor)
+DF_na$date_ch = c(NA, as.character(seq(from = Sys.Date(), by = "days", 
+                                       length.out = 9)))
+
+rhandsontable(DF_na, width = 550, height = 300)
+```
+
+### Dropdown / Autocomplete
+
+To control character column values, the column type can be specified as `dropdown` or `autocomplete`.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+# try updating big to a value not in the dropdown
+rhandsontable(DF, rowHeaders = NULL, width = 550, height = 300) %>%
+  hot_col(col = "big", type = "dropdown", source = LETTERS) %>%
+  hot_col(col = "small", type = "autocomplete", source = letters,
+          strict = FALSE)
+```
+
+### Password
+
+A column can also be specified as a `password` type.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_col("small", "password")
+```
+
+### Sparkline
+
+New in version 0.2, [sparkline.js](http://omnipotent.net/jquery.sparkline/) charts can be added to the table.  Thanks to the sparkline package and Ramnath Vaidyanathan for inspiration.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+DF$chart = c(sapply(1:5,
+                    function(x) jsonlite::toJSON(list(values=rnorm(10),
+                                                      options = list(type = "bar")))),
+             sapply(1:5,
+                    function(x) jsonlite::toJSON(list(values=rnorm(10),
+                                                      options = list(type = "line")))))
+
+rhandsontable(DF, rowHeaders = NULL, width = 550, height = 300) %>%
+  hot_col("chart", renderer = htmlwidgets::JS("renderSparkline"))
+```
+
+### Custom Renderer
+
+It's also possible to define a custom column renderer function.  For example, it may be desirable to include html in a cell.  The example below mimics [Custom renderers](http://docs.handsontable.com/0.16.1/demo-custom-renderers.html).
+
+```{r fig.height = 5, fig.width = 8}
+DF = data.frame(
+  title = c(
+    "<a href='http://www.amazon.com/Professional-JavaScript-Developers-Nicholas-Zakas/dp/1118026691'>Professional JavaScript for Web Developers</a>",
+    "<a href='http://shop.oreilly.com/product/9780596517748.do'>JavaScript: The Good Parts</a>",
+    "<a href='http://shop.oreilly.com/product/9780596805531.do'>JavaScript: The Definitive Guide</a>"
+  ),
+  desc = c(
+    "This <a href='http://bit.ly/sM1bDf'>book</a> provides a developer-level introduction along with more advanced and useful features of <b>JavaScript</b>.",
+    "This book provides a developer-level introduction along with <b>more advanced</b> and useful features of JavaScript.",
+    "<em>JavaScript: The Definitive Guide</em> provides a thorough description of the core <b>JavaScript</b> language and both the legacy and standard DOMs implemented in web browsers."
+  ),
+  comments = c(
+    "I would rate it &#x2605;&#x2605;&#x2605;&#x2605;&#x2606;",
+    "This is the book about JavaScript",
+    "I've never actually read it, but the <a href='http://shop.oreilly.com/product/9780596805531.do'>comments</a> are highly <strong>positive</strong>."
+  ), 
+  cover = c(
+    "http://ecx.images-amazon.com/images/I/51bRhyVTVGL._SL50_.jpg",
+    "http://ecx.images-amazon.com/images/I/51gdVAEfPUL._SL50_.jpg",
+    "http://ecx.images-amazon.com/images/I/51VFNL4T7kL._SL50_.jpg"
+ ),
+ stringsAsFactors = FALSE
+)
+
+rhandsontable(DF, allowedTags = "<em><b><strong><a><big>", 
+              width = 800, height = 450, rowHeaders = FALSE) %>%
+  hot_cols(colWidths = c(200, 200, 200, 80)) %>%
+  hot_col(1:2, renderer = "html") %>%
+  hot_col(1:3, renderer = htmlwidgets::JS("safeHtmlRenderer")) %>%
+  hot_col(4, renderer = "
+    function(instance, td, row, col, prop, value, cellProperties) {
+      var escaped = Handsontable.helper.stringify(value),
+        img;
+  
+      if (escaped.indexOf('http') === 0) {
+        img = document.createElement('IMG');
+        img.src = value;
+  
+        Handsontable.Dom.addEvent(img, 'mousedown', function (e){
+          e.preventDefault(); // prevent selection quirk
+        });
+  
+        Handsontable.Dom.empty(td);
+        td.appendChild(img);
+      }
+      else {
+        // render as text
+        Handsontable.renderers.TextRenderer.apply(this, arguments);
+      }
+  
+      return td;
+    }")
+```
+
+For `shiny` apps, use `renderer = htmlwidgets::JS("safeHtmlRenderer")` to display columns with html data.  The allowed html tags default to `<em><b><strong><a><big>`, but the (hidden) `allowedTags` parameter can in `rhandsontable` can be used to customize this list.
+
+#### Custom Renderer using an R Parameter {#custom_renderer_using_r}
+
+Additional parameters passed to `rhandsontable` will be available to the JavaScript widget via the `params` property.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+col_highlight = 2
+row_highlight = c(5, 7)
+
+rhandsontable(DF, col_highlight = col_highlight, 
+              row_highlight = row_highlight,
+              width = 550, height = 300) %>%
+  hot_cols(renderer = "
+    function(instance, td, row, col, prop, value, cellProperties) {
+      Handsontable.TextCell.renderer.apply(this, arguments);
+      
+      tbl = this.HTMLWidgets.widgets[0]
+
+      hcols = tbl.params.col_highlight
+      hcols = hcols instanceof Array ? hcols : [hcols] 
+      hrows = tbl.params.row_highlight
+      hrows = hrows instanceof Array ? hrows : [hrows] 
+
+      if (hcols.includes(col) && hrows.includes(row)) {
+        td.style.background = 'red';
+      }
+      else if (hcols.includes(col)) {
+        td.style.background = 'lightgreen';
+      }
+      else if (hrows.includes(row)) {
+        td.style.background = 'pink';
+      }
+      
+      return td;
+  }")
+```
+
+When using this approach in a shiny app or in a document with more than one widget, the widget search logic will need to be more robust.
+
+```
+HTMLWidgets.widgets.filter(function(widget) {
+  // this should match the table id specified in the shiny app
+  return widget.name === "hot"
+})[0];
+```
+
+## Right-Click Menu
+
+Right-clicking in a cell will enable a context menu that includes customizable table actions via the `hot_context_menu` function.  For shiny apps, formatting and comment updates made via the context menu are not currently retained.
+
+To disable the context menu, set `contextMenu = FALSE` in `hot_table` (or `rhandsontable`).
+
+### Add / Remove Rows & Columns
+
+By default a user can add or remove table rows and columns, but this functionality can be disabled.  Note that Handsontable does not allow column be added or deleted to the table if column types are defined (i.e. `useTypes == TRUE` in `rhandsontable`).
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_context_menu(allowRowEdit = FALSE, allowColEdit = FALSE)
+```
+
+### Customizing
+
+The `customOpts` parameter of `hot_context_menu` can be used to add custom functionality to the context menu.  Below are a couple examples.
+
+#### Export to CSV
+
+This example illustrates how to add an option to export the table to a csv file.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_context_menu(
+    customOpts = list(
+      csv = list(name = "Download to CSV",
+                    callback = htmlwidgets::JS(
+                      "function (key, options) {
+                         var csv = csvString(this);
+
+                         var link = document.createElement('a');
+                         link.setAttribute('href', 'data:text/plain;charset=utf-8,' +
+                           encodeURIComponent(csv));
+                         link.setAttribute('download', 'data.csv');
+
+                         document.body.appendChild(link);
+                         link.click();
+                         document.body.removeChild(link);
+                       }"))))
+```
+
+#### Search
+
+This example illustrates how to enable the search functionality in Handsontable.
+
+```{r}
+DF = data.frame(val = 1:10,
+                bool = TRUE,
+                big = LETTERS[1:10],
+                small = factor(letters[1:10]),
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, search = TRUE, width = 550, height = 300) %>%
+  hot_context_menu(
+    customOpts = list(
+      search = list(name = "Search",
+                    callback = htmlwidgets::JS(
+                      "function (key, options) {
+                         var srch = prompt('Search criteria');
+
+                         this.search.query(srch);
+                         this.render();
+                       }"))))
+```
+
+Future enhancements will look to expand export options.
+
+## Numeric Formatting
+
+Numeric columns are formatted using the [numeral.js](http://numeraljs.com/) library.
+
+```{r}
+DF = data.frame(int = 1:10, float = rnorm(10), cur = rnorm(10) * 1E5,
+                lrg = rnorm(10) * 1E8, pct = rnorm(10))
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_col("float", format = "0.0") %>%
+  hot_col("cur", format = "$0,0.00") %>%
+  hot_col("lrg", format = "0a") %>%
+  hot_col("pct", format = "0%")
+```
+
+### Specify Locale
+
+The `language` parameter for `hot_col` can be used to change the locale.  See the [numeral.js](http://numeraljs.com/) library for language options.
+
+```{r}
+DF = data.frame(dollar = rnorm(10), euro = rnorm(10), yen = rnorm(10))
+
+rhandsontable(DF * 1000, width = 550, height = 300) %>%
+  hot_col("dollar", format = "$0,000.00", language = "en-US") %>%
+  hot_col("euro", format = "0,000.00 $", language = "de-DE") %>%
+  hot_col("yen", format = "$0,000.00", language = "ja-JP")
+```
+
+## Read Only
+
+The whole table and individual columns can to set to `readOnly` to prevent the user from making changes.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, readOnly = TRUE, width = 550, height = 300) %>%
+  hot_col("val", readOnly = FALSE)
+```
+
+## Sorting
+
+Column sorting can be enabled; sorting only impacts the widget and will not reorder the original data set.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_cols(columnSorting = TRUE)
+```
+
+## Highlight Rows & Columns
+
+With larger tables it my be desirable to highlight the row and column for a selected cell.  
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+# click on a cell to see the highlighting
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_table(highlightCol = TRUE, highlightRow = TRUE)
+```
+
+See [Custom Renderer using an R Parameter](#custom_renderer_using_r) for a static highlighting example.
+
+## Sizing
+
+Column and row dimensions can be customized.  For larger data sets, (multiple) top rows and left columns can be frozen.
+
+```{r fig.height = 6, fig.width = 6}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 600, height = 600) %>%
+  hot_cols(colWidths = 100) %>%
+  hot_rows(rowHeights = 50)
+```
+
+### Row Header Width
+
+The width of the row header column can be customized using `rowHeaderWidth`.
+
+```{r fig.height = 6, fig.width = 6}
+rhandsontable(mtcars, rowHeaderWidth = 200)
+```
+
+### Streching
+
+The table can be streched to the full width by using `stretchH`.
+
+```{r fig.height = 6, fig.width = 6}
+MAT = matrix(rnorm(30), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:3]))
+
+rhandsontable(MAT, width = 600, height = 300, stretchH = "all")
+```
+
+## Fixed Rows / Columns
+
+For larger data sets, (multiple) top rows and left columns can be frozen.
+
+```{r}
+MAT = matrix(rnorm(26 * 26), nrow = 26, dimnames = list(LETTERS, letters))
+
+# scroll through the table to see the fixed row and column
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_cols(fixedColumnsLeft = 1) %>%
+  hot_rows(fixedRowsTop = 1)
+```
+
+## Cell Comments
+
+Comments (hover) can also be added to individual cells and will appear as red flags in the upper right of the cell. 
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_cell(1, 1, "Test comment")
+```
+
+Additionally, comments can be added via `data.frame` or `matrix`.
+
+```{r}
+MAT_comments = matrix(ncol = ncol(DF), nrow = nrow(DF))
+MAT_comments[1, 1] = "Test comment"
+MAT_comments[2, 2] = "Another test comment"
+
+rhandsontable(DF, comments = MAT_comments, width = 550, height = 300)
+```
+
+Finally, comments can also be added via the right-click context menu, but these updates will not currently be retained by shiny.
+
+## Borders
+
+Custom borders can be drawn around cells to highlight specific items.  Borders can also be added via the right-click context menu, but these updates will not currently be retained by shiny.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_table(customBorders = list(list(
+    range = list(from = list(row = 1, col = 1),
+                 to = list(row = 2, col = 2)),
+    top = list(width = 2, color = "red"),
+    left = list(width = 2, color = "red"),
+    bottom = list(width = 2, color = "red"),
+    right = list(width = 2, color = "red"))))
+```
+
+## Validation
+
+### Numeric Columns
+
+Pre-defined validation can be added for numeric columns in two ways:
+
+* specify a min and max and any values within the range to exclude
+* similar to a `dropdown` column, specify allowed values
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_validate_numeric(col = 1, min = -50, max = 50, exclude = 40)
+
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_validate_numeric(col = 1, choices = c(10, 20, 40))
+```
+
+### Character Columns
+
+For character columns, a vector of allowed options can be specified.  A more user-friendly approach may be to use a `dropdown` column with `strict = TRUE`.
+
+```{r}
+DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
+                small = letters[1:10],
+                dt = seq(from = Sys.Date(), by = "days", length.out = 10),
+                stringsAsFactors = FALSE)
+
+rhandsontable(DF, width = 550, height = 300) %>%
+  hot_validate_character(col = "big", choices = LETTERS[1:10])
+```
+
+### Custom
+
+It is also possible to create a custom validation function in JavaScript.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+# try to update any cell to 0
+rhandsontable(MAT * 10, width = 550, height = 300) %>%
+  hot_cols(validator = "
+           function (value, callback) {
+            setTimeout(function(){
+              callback(value != 0);
+            }, 1000)
+           }",
+           allowInvalid = FALSE)
+```
+
+## Conditional Formatting
+
+Conditional formatting can also be specified via custom JavaScript function.  Future enhancements will look to simplify this interface.
+
+```{r, fig.width = 8}
+MAT = matrix(runif(100, -1, 1), nrow = 10,
+             dimnames = list(LETTERS[1:10], LETTERS[1:10]))
+diag(MAT) = 1
+MAT[upper.tri(MAT)] = MAT[lower.tri(MAT)]
+rhandsontable(MAT, readOnly = TRUE, width = 750, height = 300) %>%
+  hot_cols(renderer = "
+           function (instance, td, row, col, prop, value, cellProperties) {
+             Handsontable.renderers.TextRenderer.apply(this, arguments);
+             if (row == col) {
+              td.style.background = 'lightgrey';
+             } else if (col > row) {
+              td.style.background = 'grey';
+              td.style.color = 'grey';
+             } else if (value < -0.75) {
+              td.style.background = 'pink';
+             } else if (value > 0.75) {
+              td.style.background = 'lightgreen';
+             }
+           }")
+```
+
+See [Custom Renderer using an R Parameter](#custom_renderer_using_r) for anotehr example.
+
+## Heatmap
+
+The [chroma.js](http://old.driven-by-data.net/about/chromajs/) library can be used to turn the table into a heatmap.
+
+```{r}
+MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
+                                                   letters[1:5]))
+
+rhandsontable(MAT, width = 550, height = 300) %>%
+  hot_heatmap()
+```
+
+## Big Data
+
+```{r}
+MAT = matrix(rnorm(10000 * 100), nrow = 100, dimnames= list(1:100, 1:10000))
+
+rhandsontable(MAT, width = 550, height = 550)
+```
+
+## Shiny
+
+**Important note on shiny use:** The `htmlwidgets` package creates widgets as shiny output bindings.  The `rhandsontable` package also attempts to expose the table as a *pseudo* shiny input binding using handsontable change events (see [here](https://github.com/jrowen/rhandsontable/blob/master/inst/htmlwidgets/rhandsontable.js) for the supported events).  **This means the table (e.g. `hot`) can be accessed in shiny using either `input$hot` or `output$hot`, but these values may not be in- [...]
+
+Since the widget is not currently able to use the standard shiny input binding functionality, you will need to explicitly call the `hot_to_r` function to convert the handsontable data to an R object.
+
+Two additional inputs are also enabled, `input$hot_select` and `input$hot_comment`, which will fire when a cell selection or a comment changes, respectively (if you would like to see more options, please post an issue or create a PR).
+
+This functionality is still evolving, so please don't hesitate to share suggestions and PRs.
+
+The data grid will be editable by default and can be used as input to a `shiny` app.  A few `shiny` and `shinydashboard` example links are listed below.  Note that the shinyapps.io links may not work if the has hit the monthly usage limit.
+
+* [Output only](https://jrowen.shinyapps.io/rhandsontable_output)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_output")
+```
+* [Date file editor](https://jrowen.shinyapps.io/rhandsontable_datafile)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_datafile")
+```
+* [Calculation input](https://jrowen.shinyapps.io/rhandsontable_portfolio)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_portfolio")
+```
+* [Table callback linked to chart](https://jrowen.shinyapps.io/rhandsontable_corr)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_corr")
+```
+* [Multiple input tables](https://jrowen.shinyapps.io/rhandsontable_frontier)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir = "inst/examples/rhandsontable_frontier")
+```
+* [A shinydashboard app](https://jrowen.shinyapps.io/rhandsontable_dash)
+```
+shiny::runGitHub("rhandsontable", "jrowen", 
+                 subdir="inst/examples/rhandsontable_dash")
+```
+
+### Bookmarks
+
+Version 0.14 of `shiny` includes new bookmarking functionality.  This willl work for `rhandsontable` with some special handling.  See [this issue](https://github.com/rstudio/shiny/issues/1378) for more details.
+
+## Suggestions & Contributions
+
+Please file a issue if you experience any problems with the widget or have feature requests.  Pull requests are also welcome.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-rhandsontable.git



More information about the debian-med-commit mailing list