├── .gitignore
├── .idea
├── misc.xml
├── modules.xml
├── pyhandsontable.iml
└── vcs.xml
├── .travis.yml
├── LICENSE
├── README.md
├── pyhandsontable
├── __init__.py
├── core.py
├── pagination.py
└── templates
│ ├── handsontable.full.min.css
│ ├── handsontable.full.min.js
│ ├── sheet.html
│ └── sheet.js
├── pyproject.lock
├── pyproject.toml
├── screenshots
├── 0.png
└── 1.png
└── tests
├── __init__.py
├── output
└── .gitignore
└── test_generate.py
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/linux,python,pycharm,jupyternotebook
3 |
4 | ### JupyterNotebook ###
5 | .ipynb_checkpoints
6 | */.ipynb_checkpoints/*
7 |
8 | # Remove previous ipynb_checkpoints
9 | # git rm -r .ipynb_checkpoints/
10 | #
11 |
12 | ### Linux ###
13 | *~
14 |
15 | # temporary files which can be created if a process still has a handle open of a deleted file
16 | .fuse_hidden*
17 |
18 | # KDE directory preferences
19 | .directory
20 |
21 | # Linux trash folder which might appear on any partition or disk
22 | .Trash-*
23 |
24 | # .nfs files are created when an open file is removed but is still being accessed
25 | .nfs*
26 |
27 | ### PyCharm ###
28 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
29 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
30 |
31 | # User-specific stuff
32 | .idea/**/workspace.xml
33 | .idea/**/tasks.xml
34 | .idea/**/usage.statistics.xml
35 | .idea/**/dictionaries
36 | .idea/**/shelf
37 |
38 | # Sensitive or high-churn files
39 | .idea/**/dataSources/
40 | .idea/**/dataSources.ids
41 | .idea/**/dataSources.local.xml
42 | .idea/**/sqlDataSources.xml
43 | .idea/**/dynamic.xml
44 | .idea/**/uiDesigner.xml
45 | .idea/**/dbnavigator.xml
46 |
47 | # Gradle
48 | .idea/**/gradle.xml
49 | .idea/**/libraries
50 |
51 | # Gradle and Maven with auto-import
52 | # When using Gradle or Maven with auto-import, you should exclude module files,
53 | # since they will be recreated, and may cause churn. Uncomment if using
54 | # auto-import.
55 | # .idea/modules.xml
56 | # .idea/*.iml
57 | # .idea/modules
58 |
59 | # CMake
60 | cmake-build-*/
61 |
62 | # Mongo Explorer plugin
63 | .idea/**/mongoSettings.xml
64 |
65 | # File-based project format
66 | *.iws
67 |
68 | # IntelliJ
69 | out/
70 |
71 | # mpeltonen/sbt-idea plugin
72 | .idea_modules/
73 |
74 | # JIRA plugin
75 | atlassian-ide-plugin.xml
76 |
77 | # Cursive Clojure plugin
78 | .idea/replstate.xml
79 |
80 | # Crashlytics plugin (for Android Studio and IntelliJ)
81 | com_crashlytics_export_strings.xml
82 | crashlytics.properties
83 | crashlytics-build.properties
84 | fabric.properties
85 |
86 | # Editor-based Rest Client
87 | .idea/httpRequests
88 |
89 | ### PyCharm Patch ###
90 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
91 |
92 | # *.iml
93 | # modules.xml
94 | # .idea/misc.xml
95 | # *.ipr
96 |
97 | # Sonarlint plugin
98 | .idea/sonarlint
99 |
100 | ### Python ###
101 | # Byte-compiled / optimized / DLL files
102 | __pycache__/
103 | *.py[cod]
104 | *$py.class
105 |
106 | # C extensions
107 | *.so
108 |
109 | # Distribution / packaging
110 | .Python
111 | build/
112 | develop-eggs/
113 | dist/
114 | downloads/
115 | eggs/
116 | .eggs/
117 | lib/
118 | lib64/
119 | parts/
120 | sdist/
121 | var/
122 | wheels/
123 | *.egg-info/
124 | .installed.cfg
125 | *.egg
126 | MANIFEST
127 |
128 | # PyInstaller
129 | # Usually these files are written by a python script from a template
130 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
131 | *.manifest
132 | *.spec
133 |
134 | # Installer logs
135 | pip-log.txt
136 | pip-delete-this-directory.txt
137 |
138 | # Unit test / coverage reports
139 | htmlcov/
140 | .tox/
141 | .coverage
142 | .coverage.*
143 | .cache
144 | nosetests.xml
145 | coverage.xml
146 | *.cover
147 | .hypothesis/
148 | .pytest_cache/
149 |
150 | # Translations
151 | *.mo
152 | *.pot
153 |
154 | # Django stuff:
155 | *.log
156 | local_settings.py
157 | db.sqlite3
158 |
159 | # Flask stuff:
160 | instance/
161 | .webassets-cache
162 |
163 | # Scrapy stuff:
164 | .scrapy
165 |
166 | # Sphinx documentation
167 | docs/_build/
168 |
169 | # PyBuilder
170 | target/
171 |
172 | # Jupyter Notebook
173 |
174 | # pyenv
175 | .python-version
176 |
177 | # celery beat schedule file
178 | celerybeat-schedule
179 |
180 | # SageMath parsed files
181 | *.sage.py
182 |
183 | # Environments
184 | .env
185 | .venv
186 | env/
187 | venv/
188 | ENV/
189 | env.bak/
190 | venv.bak/
191 |
192 | # Spyder project settings
193 | .spyderproject
194 | .spyproject
195 |
196 | # Rope project settings
197 | .ropeproject
198 |
199 | # mkdocs documentation
200 | /site
201 |
202 | # mypy
203 | .mypy_cache/
204 |
205 | ### Python Patch ###
206 | .venv/
207 |
208 |
209 | # End of https://www.gitignore.io/api/linux,python,pycharm,jupyternotebook
210 |
211 | setup.py
212 | .idea/*
213 | .vscode/*
214 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/pyhandsontable.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "3.5"
4 | - "3.6"
5 | # - "3.7-dev" Currently running 3.7 on Ubuntu
6 |
7 | install:
8 | - "curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python"
9 | - "poetry install"
10 |
11 | script:
12 | - "pytest"
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Pacharapol Withayasakpunt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pyhandsontable
2 |
3 | [](https://travis-ci.org/patarapolw/pyhandsontable)
4 | [](https://pypi.python.org/pypi/pyhandsontable/)
5 | [](https://pypi.python.org/pypi/pyhandsontable/)
6 | [](https://pypi.python.org/pypi/pyhandsontable/)
7 |
8 | View a list of JSON-serializable dictionaries or a 2-D array, in HandsOnTable, in Jupyter Notebook.
9 |
10 | Nested JSON renderer is also supported and is default. Image and markdown renderers are possible, but has to be extended.
11 |
12 | ## Installation
13 |
14 | ```commandline
15 | pip install pyhandsontable
16 | ```
17 |
18 | ## Usage
19 |
20 | In Jupyter Notebook,
21 |
22 | ```python
23 | >>> from pyhandsontable import PagedViewer
24 | >>> viewer = PagedViewer(data=data_matrix, **kwargs)
25 | >>> viewer
26 | 'A Handsontable is shown in Jupyter Notebook.'
27 | >>> viewer.view(-1)
28 | 'The last page is shown.'
29 | >>> viewer.previous()
30 | 'The previous page (i-1) is shown.'
31 | >>> viewer.next()
32 | 'The next page (i+1) is shown.'
33 | ```
34 |
35 | Data matrix can be either a list of lists (2-D array) or a list of dictionaries.
36 |
37 | It is also possible to view all entries at once, but it could be bad, if there are too many rows.
38 |
39 | ```python
40 | >>> from pyhandsontable import view_table
41 | >>> view_table(data_matrix, **kwargs)
42 | ```
43 |
44 | ## Acceptable kwargs
45 |
46 | - height: height of the window (default: 500)
47 | - width: width of the window (default: 1000)
48 | - title: title of the HTML file
49 | - maxColWidth: maximum column width. (Default: 200)
50 | - renderers: the renderers to use in generating the columns (see below.)
51 | - autodelete: whether the temporary HTML file should be autodeleted. (Default: True)
52 | - filename: filename of the temporary HTML file (default: 'temp.handsontable.html')
53 | - config: add additional config as defined in https://docs.handsontable.com/pro/5.0.0/tutorial-introduction.html
54 | - This will override the default config (per key basis) which are:
55 |
56 | ```javascript
57 | {
58 | data: data,
59 | rowHeaders: true,
60 | colHeaders: true,
61 | columns: columns,
62 | manualColumnResize: true,
63 | manualRowResize: true,
64 | renderAllRows: true,
65 | modifyColWidth: (width, col)=>{
66 | if(width > maxColWidth) return maxColWidth;
67 | },
68 | afterRenderer: (td, row, column, prop, value, cellProperties)=>{
69 | td.innerHTML = '
';
70 | }
71 | }
72 | ```
73 |
74 | `renderers` example, if your data is a 2-D array:
75 |
76 | ```python
77 | {
78 | 1: 'html',
79 | 2: 'html'
80 | }
81 | ```
82 |
83 | or if your data is list of dict:
84 |
85 | ```python
86 | {
87 | "front": 'html',
88 | "back": 'html'
89 | }
90 | ```
91 |
92 | ## Enabling Image, HTML and Markdown renderer
93 |
94 | This can be done in Python side, by converting everything to HTML. Just use [any markdown for Python library](https://github.com/Python-Markdown/markdown).
95 |
96 | ```python
97 | from markdown import markdown
98 | import base64
99 | image_html = f'
'
100 | image_html2 = f'
'
101 | markdown_html = markdown(markdown_raw)
102 | ```
103 |
104 | Any then,
105 |
106 | ```python
107 | PagedViewer(data=data_matrix, renderers={
108 | "image_field": "html",
109 | "html_field": "html",
110 | "markdown_field": "html"
111 | })
112 | ```
113 |
114 | ## Screenshots
115 |
116 | 
117 | 
118 |
119 | ## Related projects
120 |
121 | - [htmlviewer](https://github.com/patarapolw/htmlviewer) - similar in concept to this project, but does not use HandsOnTable.js
122 | - [TinyDB-viewer](https://github.com/patarapolw/tinydb-viewer) - uses HandsOnTable.js and also allow editing in Jupyter Notebook.
123 |
124 | ## License
125 |
126 | This software includes [`handsontable.js`](https://github.com/handsontable/handsontable), which is MIT-licensed.
127 |
--------------------------------------------------------------------------------
/pyhandsontable/__init__.py:
--------------------------------------------------------------------------------
1 | from .core import generate_html, view_table
2 | from .pagination import PagedViewer
3 |
--------------------------------------------------------------------------------
/pyhandsontable/core.py:
--------------------------------------------------------------------------------
1 | from jinja2 import Environment, PackageLoader
2 | from threading import Timer
3 | import os
4 | from collections import OrderedDict
5 | from IPython.display import IFrame
6 |
7 | env = Environment(
8 | loader=PackageLoader('pyhandsontable', 'templates')
9 | )
10 |
11 |
12 | def generate_html(data, **kwargs):
13 | renderers = kwargs.pop('renderers', dict())
14 | config = kwargs.pop('config', dict())
15 |
16 | if isinstance(data[0], (dict, OrderedDict)):
17 | headers = sum((list(d.keys()) for d in data), list())
18 | headers = [h for i, h in enumerate(headers) if h not in headers[:i]]
19 | config['colHeaders'] = list(headers)
20 | else:
21 | headers = range(len(data[0]))
22 |
23 | columns = []
24 | for header in headers:
25 | columnData = {
26 | 'data': header,
27 | 'renderer': 'jsonRenderer'
28 | }
29 | if header in renderers.keys():
30 | columnData['renderer'] = renderers.get(header)
31 | columns.append(columnData)
32 |
33 | template = env.get_template('sheet.html')
34 |
35 | return template.render(data=data, columns=columns, config=config, **kwargs)
36 |
37 |
38 | def view_table(data, width=1000, height=500,
39 | filename='temp.handsontable.html', autodelete=True, **kwargs):
40 | # A TemporaryFile does not work with Jupyter Notebook
41 |
42 | try:
43 | with open(filename, 'w') as f:
44 | f.write(generate_html(data=data, width=width, height=height, **kwargs))
45 |
46 | return IFrame(filename, width=width, height=height)
47 | finally:
48 | if autodelete:
49 | Timer(5, os.unlink, args=[filename]).start()
50 |
--------------------------------------------------------------------------------
/pyhandsontable/pagination.py:
--------------------------------------------------------------------------------
1 | from IPython.display import display
2 | import math
3 |
4 | from .core import view_table
5 |
6 |
7 | class PagedViewer:
8 | chunk_size = 10
9 | i = 0
10 |
11 | def __init__(self,
12 | records,
13 | chunk_size=10,
14 | **kwargs):
15 | self.records = list(records)
16 | self.chunk_size = chunk_size
17 | self.viewer_kwargs = kwargs
18 | self.viewer_kwargs.setdefault('config', dict()).setdefault('rowHeaders', False)
19 |
20 | @property
21 | def num_pages(self):
22 | return math.ceil(len(self.records) / self.chunk_size)
23 |
24 | @property
25 | def num_records(self):
26 | return len(self.records)
27 |
28 | def __len__(self):
29 | return self.num_records
30 |
31 | def _repr_html_(self):
32 | display(self.view())
33 | return ''
34 |
35 | def view(self, page_number = None, start = None):
36 | """Choose a page number to view
37 |
38 | Keyword Arguments:
39 | page_number {int >= -1} -- Page number to view (default: {self.i})
40 | start {int} -- Sequence of the record to start viewing (default: {None})
41 |
42 | Returns:
43 | Viewer function object
44 | """
45 |
46 | if page_number is None:
47 | page_number = self.i
48 | elif page_number == -1:
49 | page_number = self.num_pages -1
50 |
51 | self.i = page_number
52 |
53 | if start is None:
54 | start = page_number * self.chunk_size
55 |
56 | return view_table(self.records[start: start + self.chunk_size], **self.viewer_kwargs)
57 |
58 | def next(self):
59 | """Shows the next page
60 |
61 | Returns:
62 | Viewer function object
63 | """
64 |
65 | if len(self.records) < (self.i + 1) * self.chunk_size:
66 | self.i = 0
67 | else:
68 | self.i += 1
69 |
70 | return self.view()
71 |
72 | def previous(self):
73 | """Show the previous page
74 |
75 | Returns:
76 | Viewer function object
77 | """
78 |
79 | self.i -= 1
80 | if self.i < 0:
81 | self.i = self.num_pages - 1
82 |
83 | return self.view()
84 |
85 | def first(self):
86 | """Shows the first page
87 |
88 | Returns:
89 | Viewer function object
90 | """
91 |
92 | return self.view(0)
93 |
94 | def last(self):
95 | """Shows the last page
96 |
97 | Returns:
98 | Viewer function object
99 | """
100 |
101 | return self.view(-1)
102 |
--------------------------------------------------------------------------------
/pyhandsontable/templates/handsontable.full.min.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | /*!
3 | * (The MIT License)
4 | *
5 | * Copyright (c) 2012-2014 Marcin Warpechowski
6 | * Copyright (c) 2015 Handsoncode sp. z o.o.
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * 'Software'), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | *
27 | * Version: 6.0.1
28 | * Release date: 02/10/2018 (built at 02/10/2018 11:30:48)
29 | */.handsontable .table td,.handsontable .table th{border-top:none}.handsontable tr{background:#fff}.handsontable td{background-color:inherit}.handsontable .table caption+thead tr:first-child td,.handsontable .table caption+thead tr:first-child th,.handsontable .table colgroup+thead tr:first-child td,.handsontable .table colgroup+thead tr:first-child th,.handsontable .table thead:first-child tr:first-child td,.handsontable .table thead:first-child tr:first-child th{border-top:1px solid #ccc}.handsontable .table-bordered{border:0;border-collapse:separate}.handsontable .table-bordered td,.handsontable .table-bordered th{border-left:none}.handsontable .table-bordered td:first-child,.handsontable .table-bordered th:first-child{border-left:1px solid #ccc}.handsontable .table>tbody>tr>td,.handsontable .table>tbody>tr>th,.handsontable .table>tfoot>tr>td,.handsontable .table>tfoot>tr>th,.handsontable .table>thead>tr>td,.handsontable .table>thead>tr>th{line-height:21px;padding:0 4px}.col-lg-1.handsontable,.col-lg-2.handsontable,.col-lg-3.handsontable,.col-lg-4.handsontable,.col-lg-5.handsontable,.col-lg-6.handsontable,.col-lg-7.handsontable,.col-lg-8.handsontable,.col-lg-9.handsontable,.col-lg-10.handsontable,.col-lg-11.handsontable,.col-lg-12.handsontable,.col-md-1.handsontable,.col-md-2.handsontable,.col-md-3.handsontable,.col-md-4.handsontable,.col-md-5.handsontable,.col-md-6.handsontable,.col-md-7.handsontable,.col-md-8.handsontable,.col-md-9.handsontable .col-sm-1.handsontable,.col-md-10.handsontable,.col-md-11.handsontable,.col-md-12.handsontable,.col-sm-2.handsontable,.col-sm-3.handsontable,.col-sm-4.handsontable,.col-sm-5.handsontable,.col-sm-6.handsontable,.col-sm-7.handsontable,.col-sm-8.handsontable,.col-sm-9.handsontable .col-xs-1.handsontable,.col-sm-10.handsontable,.col-sm-11.handsontable,.col-sm-12.handsontable,.col-xs-2.handsontable,.col-xs-3.handsontable,.col-xs-4.handsontable,.col-xs-5.handsontable,.col-xs-6.handsontable,.col-xs-7.handsontable,.col-xs-8.handsontable,.col-xs-9.handsontable,.col-xs-10.handsontable,.col-xs-11.handsontable,.col-xs-12.handsontable{padding-left:0;padding-right:0}.handsontable .table-striped>tbody>tr:nth-of-type(2n){background-color:#fff}.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 div,.handsontable input,.handsontable table,.handsontable tbody,.handsontable td,.handsontable textarea,.handsontable th,.handsontable thead{box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box}.handsontable input,.handsontable textarea{min-height:0}.handsontable table.htCore{border-collapse:separate;border-spacing:0;margin:0;border-width:0;table-layout:fixed;width:0;outline-width:0;cursor:default;max-width:none;max-height:none}.handsontable col,.handsontable col.rowHeader{width:50px}.handsontable td,.handsontable th{border-top-width:0;border-left-width:0;border-right:1px solid #ccc;border-bottom:1px solid #ccc;height:22px;empty-cells:show;line-height:21px;padding:0 4px;background-color:#fff;vertical-align:top;overflow:hidden;outline-width:0;white-space:pre-line;background-clip:padding-box}.handsontable td.htInvalid{background-color:#ff4c42!important}.handsontable td.htNoWrap{white-space:nowrap}.handsontable th:last-child{border-right:1px solid #ccc;border-bottom:1px solid #ccc}.handsontable th.htNoFrame,.handsontable th:first-child.htNoFrame,.handsontable tr:first-child th.htNoFrame{border-left-width:0;background-color:#fff;border-color:#fff}.handsontable .htNoFrame+td,.handsontable .htNoFrame+th,.handsontable.htRowHeaders thead tr th:nth-child(2),.handsontable td:first-of-type,.handsontable th:first-child,.handsontable th:nth-child(2){border-left:1px solid #ccc}.handsontable tr:first-child td,.handsontable tr:first-child th{border-top:1px solid #ccc}.ht_master:not(.innerBorderLeft):not(.emptyColumns)~.handsontable:not(.ht_clone_top) thead tr th:first-child,.ht_master:not(.innerBorderLeft):not(.emptyColumns)~.handsontable tbody tr th{border-right-width:0}.ht_master:not(.innerBorderTop) thead tr.lastChild th,.ht_master:not(.innerBorderTop) thead tr:last-child th,.ht_master:not(.innerBorderTop)~.handsontable thead tr.lastChild th,.ht_master:not(.innerBorderTop)~.handsontable thead tr:last-child th{border-bottom-width:0}.handsontable th{background-color:#f0f0f0;color:#222;text-align:center;font-weight:400;white-space:nowrap}.handsontable thead th{padding:0}.handsontable th.active{background-color:#ccc}.handsontable thead th .relative{padding:2px 4px}#hot-display-license-info{font-size:10px;color:#323232;padding:5px 0 3px;font-family:Helvetica,Arial,sans-serif;text-align:left}.handsontable .manualColumnResizer{position:fixed;top:0;cursor:col-resize;z-index:110;width:5px;height:25px}.handsontable .manualRowResizer{position:fixed;left:0;cursor:row-resize;z-index:110;height:5px;width:50px}.handsontable .manualColumnResizer.active,.handsontable .manualColumnResizer:hover,.handsontable .manualRowResizer.active,.handsontable .manualRowResizer:hover{background-color:#34a9db}.handsontable .manualColumnResizerGuide{position:fixed;right:0;top:0;background-color:#34a9db;display:none;width:0;border-right:1px dashed #777;margin-left:5px}.handsontable .manualRowResizerGuide{position:fixed;left:0;bottom:0;background-color:#34a9db;display:none;height:0;border-bottom:1px dashed #777;margin-top:5px}.handsontable .manualColumnResizerGuide.active,.handsontable .manualRowResizerGuide.active{display:block;z-index:199}.handsontable .columnSorting{position:relative}.handsontable .columnSorting.sortAction:hover{text-decoration:underline;cursor:pointer}.handsontable span.colHeader{display:inline-block;line-height:1.1}.handsontable span.colHeader.columnSorting:before{top:50%;margin-top:-6px;padding-left:8px;position:absolute;right:-9px;content:"";height:10px;width:5px;background-size:contain;background-repeat:no-repeat;background-position-x:right}.handsontable span.colHeader.columnSorting.ascending:before{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAMAAADJ7yrpAAAAKlBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKE86IAAAADXRSTlMABBEmRGprlJW72e77tTkTKwAAAFNJREFUeAHtzjkSgCAUBNHPgsoy97+ulGXRqJE5L+xkxoYt2UdsLb5bqFINz+aLuuLn5rIu2RkO3fZpWENimNgiw6iBYRTPMLJjGFxQZ1hxxb/xBI1qC8k39CdKAAAAAElFTkSuQmCC")}.handsontable span.colHeader.columnSorting.descending:before{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAMAAADJ7yrpAAAAKlBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKE86IAAAADXRSTlMABBEmRGprlJW72e77tTkTKwAAAFJJREFUeAHtzjkSgCAQRNFmQYUZ7n9dKUvru0TmvPAn3br0QfgdZ5xx6x+rQn23GqTYnq1FDcnuzZIO2WmedVqIRVxgGKEyjNgYRjKGkZ1hFIZ3I70LyM0VtU8AAAAASUVORK5CYII=")}.htGhostTable .htCore span.colHeader.columnSorting:not(.indicatorDisabled):after{content:"*";display:inline-block;position:relative;padding-right:20px}.handsontable .wtBorder{position:absolute;font-size:0}.handsontable .wtBorder.hidden{display:none!important}.handsontable .wtBorder.current{z-index:10}.handsontable .wtBorder.area{z-index:8}.handsontable .wtBorder.fill{z-index:6}.handsontable td.area,.handsontable td.area-1,.handsontable td.area-2,.handsontable td.area-3,.handsontable td.area-4,.handsontable td.area-5,.handsontable td.area-6,.handsontable td.area-7{position:relative}.handsontable td.area-1:before,.handsontable td.area-2:before,.handsontable td.area-3:before,.handsontable td.area-4:before,.handsontable td.area-5:before,.handsontable td.area-6:before,.handsontable td.area-7:before,.handsontable td.area:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;bottom:-100%\9;background:#005eff}@media (-ms-high-contrast:none),screen and (-ms-high-contrast:active){.handsontable td.area-1:before,.handsontable td.area-2:before,.handsontable td.area-3:before,.handsontable td.area-4:before,.handsontable td.area-5:before,.handsontable td.area-6:before,.handsontable td.area-7:before,.handsontable td.area:before{bottom:-100%}}.handsontable td.area:before{opacity:.1}.handsontable td.area-1:before{opacity:.2}.handsontable td.area-2:before{opacity:.27}.handsontable td.area-3:before{opacity:.35}.handsontable td.area-4:before{opacity:.41}.handsontable td.area-5:before{opacity:.47}.handsontable td.area-6:before{opacity:.54}.handsontable td.area-7:before{opacity:.58}.handsontable tbody th.ht__highlight,.handsontable thead th.ht__highlight{background-color:#dcdcdc}.handsontable tbody th.ht__active_highlight,.handsontable thead th.ht__active_highlight{background-color:#8eb0e7;color:#000}.handsontable .wtBorder.corner{font-size:0;cursor:crosshair}.handsontable .htBorder.htFillBorder{background:red;width:1px;height:1px}.handsontableInput{border:none;outline-width:0;margin:0;padding:1px 5px 0;font-family:inherit;line-height:21px;font-size:inherit;box-shadow:inset 0 0 0 2px #5292f7;resize:none;display:block;color:#000;border-radius:0;background-color:#fff}.handsontableInputHolder{position:absolute;top:0;left:0;z-index:104}.htSelectEditor{-webkit-appearance:menulist-button!important;position:absolute;width:auto}.handsontable .htDimmed{color:#777}.handsontable .htSubmenu{position:relative}.handsontable .htSubmenu :after{content:"\25B6";color:#777;position:absolute;right:5px;font-size:9px}.handsontable .htLeft{text-align:left}.handsontable .htCenter{text-align:center}.handsontable .htRight{text-align:right}.handsontable .htJustify{text-align:justify}.handsontable .htTop{vertical-align:top}.handsontable .htMiddle{vertical-align:middle}.handsontable .htBottom{vertical-align:bottom}.handsontable .htPlaceholder{color:#999}.handsontable .htAutocompleteArrow{float:right;font-size:10px;color:#eee;cursor:default;width:16px;text-align:center}.handsontable td .htAutocompleteArrow:hover{color:#777}.handsontable td.area .htAutocompleteArrow{color:#d3d3d3}.handsontable .htCheckboxRendererInput{display:inline-block;vertical-align:middle}.handsontable .htCheckboxRendererInput.noValue{opacity:.5}.handsontable .htCheckboxRendererLabel{cursor:pointer;display:inline-block;width:100%}.handsontable .handsontable.ht_clone_top .wtHider{padding:0 0 5px}.handsontable .autocompleteEditor.handsontable{padding-right:17px}.handsontable .autocompleteEditor.handsontable.htMacScroll{padding-right:15px}.handsontable.listbox{margin:0}.handsontable.listbox .ht_master table{border:1px solid #ccc;border-collapse:separate;background:#fff}.handsontable.listbox td,.handsontable.listbox th,.handsontable.listbox tr:first-child td,.handsontable.listbox tr:first-child th,.handsontable.listbox tr:last-child th{border-color:transparent}.handsontable.listbox td,.handsontable.listbox th{white-space:nowrap;text-overflow:ellipsis}.handsontable.listbox td.htDimmed{cursor:default;color:inherit;font-style:inherit}.handsontable.listbox .wtBorder{visibility:hidden}.handsontable.listbox tr:hover td,.handsontable.listbox tr td.current{background:#eee}.ht_clone_top{z-index:101}.ht_clone_left{z-index:102}.ht_clone_bottom_left_corner,.ht_clone_debug,.ht_clone_top_left_corner{z-index:103}.handsontable td.htSearchResult{background:#fcedd9;color:#583707}.htBordered{border-width:1px}.htBordered.htTopBorderSolid{border-top-style:solid;border-top-color:#000}.htBordered.htRightBorderSolid{border-right-style:solid;border-right-color:#000}.htBordered.htBottomBorderSolid{border-bottom-style:solid;border-bottom-color:#000}.htBordered.htLeftBorderSolid{border-left-style:solid;border-left-color:#000}.handsontable tbody tr th:nth-last-child(2){border-right:1px solid #ccc}.handsontable thead tr:nth-last-child(2) th.htGroupIndicatorContainer{border-bottom:1px solid #ccc;padding-bottom:5px}.ht_clone_top_left_corner thead tr th:nth-last-child(2){border-right:1px solid #ccc}.htCollapseButton{width:10px;height:10px;line-height:10px;text-align:center;border-radius:5px;border:1px solid #f3f3f3;box-shadow:1px 1px 3px rgba(0,0,0,.4);cursor:pointer;margin-bottom:3px;position:relative}.htCollapseButton:after{content:"";height:300%;width:1px;display:block;background:#ccc;margin-left:4px;position:absolute;bottom:10px}thead .htCollapseButton{right:5px;position:absolute;top:5px;background:#fff}thead .htCollapseButton:after{height:1px;width:700%;right:10px;top:4px}.handsontable tr th .htExpandButton{position:absolute;width:10px;height:10px;line-height:10px;text-align:center;border-radius:5px;border:1px solid #f3f3f3;box-shadow:1px 1px 3px rgba(0,0,0,.4);cursor:pointer;top:0;display:none}.handsontable thead tr th .htExpandButton{top:5px}.handsontable tr th .htExpandButton.clickable{display:block}.collapsibleIndicator{position:absolute;top:50%;transform:translateY(-50%);right:5px;border:1px solid #a6a6a6;line-height:10px;color:#222;border-radius:10px;font-size:10px;width:10px;height:10px;cursor:pointer;box-shadow:0 0 0 6px #eee;background:#eee}.handsontable col.hidden{width:0!important}.handsontable table tr th.lightRightBorder{border-right:1px solid #e6e6e6}.handsontable tr.hidden,.handsontable tr.hidden td,.handsontable tr.hidden th{display:none}.ht_clone_bottom,.ht_clone_left,.ht_clone_top,.ht_master{overflow:hidden}.ht_master .wtHolder{overflow:auto}.handsontable .ht_clone_left thead,.handsontable .ht_master thead,.handsontable .ht_master tr th{visibility:hidden}.ht_clone_bottom .wtHolder,.ht_clone_left .wtHolder,.ht_clone_top .wtHolder{overflow:hidden}.handsontable.mobile,.handsontable.mobile .wtHolder{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-overflow-scrolling:touch}.htMobileEditorContainer{display:none;position:absolute;top:0;width:70%;height:54pt;background:#f8f8f8;border-radius:20px;border:1px solid #ebebeb;z-index:999;box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-text-size-adjust:none}.topLeftSelectionHandle-HitArea:not(.ht_master .topLeftSelectionHandle-HitArea),.topLeftSelectionHandle:not(.ht_master .topLeftSelectionHandle){z-index:9999}.bottomRightSelectionHandle,.bottomRightSelectionHandle-HitArea,.topLeftSelectionHandle,.topLeftSelectionHandle-HitArea{left:-10000px;top:-10000px}.htMobileEditorContainer.active{display:block}.htMobileEditorContainer .inputs{position:absolute;right:210pt;bottom:10pt;top:10pt;left:14px;height:34pt}.htMobileEditorContainer .inputs textarea{font-size:13pt;border:1px solid #a1a1a1;-webkit-appearance:none;box-shadow:none;position:absolute;left:14px;right:14px;top:0;bottom:0;padding:7pt}.htMobileEditorContainer .cellPointer{position:absolute;top:-13pt;height:0;width:0;left:30px;border-left:13pt solid transparent;border-right:13pt solid transparent;border-bottom:13pt solid #ebebeb}.htMobileEditorContainer .cellPointer.hidden{display:none}.htMobileEditorContainer .cellPointer:before{content:"";display:block;position:absolute;top:2px;height:0;width:0;left:-13pt;border-left:13pt solid transparent;border-right:13pt solid transparent;border-bottom:13pt solid #f8f8f8}.htMobileEditorContainer .moveHandle{position:absolute;top:10pt;left:5px;width:30px;bottom:0;cursor:move;z-index:9999}.htMobileEditorContainer .moveHandle:after{content:"..\A..\A..\A..";white-space:pre;line-height:10px;font-size:20pt;display:inline-block;margin-top:-8px;color:#ebebeb}.htMobileEditorContainer .positionControls{width:205pt;position:absolute;right:5pt;top:0;bottom:0}.htMobileEditorContainer .positionControls>div{width:50pt;height:100%;float:left}.htMobileEditorContainer .positionControls>div:after{content:" ";display:block;width:15pt;height:15pt;text-align:center;line-height:50pt}.htMobileEditorContainer .downButton:after,.htMobileEditorContainer .leftButton:after,.htMobileEditorContainer .rightButton:after,.htMobileEditorContainer .upButton:after{transform-origin:5pt 5pt;-webkit-transform-origin:5pt 5pt;margin:21pt 0 0 21pt}.htMobileEditorContainer .leftButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(-45deg)}.htMobileEditorContainer .leftButton:active:after{border-color:#cfcfcf}.htMobileEditorContainer .rightButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(135deg)}.htMobileEditorContainer .rightButton:active:after{border-color:#cfcfcf}.htMobileEditorContainer .upButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(45deg)}.htMobileEditorContainer .upButton:active:after{border-color:#cfcfcf}.htMobileEditorContainer .downButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(225deg)}.htMobileEditorContainer .downButton:active:after{border-color:#cfcfcf}.handsontable.hide-tween{animation:opacity-hide .3s;animation-fill-mode:forwards;-webkit-animation-fill-mode:forwards}.handsontable.show-tween{animation:opacity-show .3s;animation-fill-mode:forwards;-webkit-animation-fill-mode:forwards}
30 |
31 | /*!
32 | * Pikaday
33 | * Copyright © 2014 David Bushell | BSD & MIT license | http://dbushell.com/
34 | */.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:after,.pika-single:before{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:relative;text-align:center}.pika-label{display:inline-block;*display:inline;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:none;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:50%;background-repeat:no-repeat;background-size:75% 75%;opacity:.5;*position:absolute;*top:0}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==");*left:0}.is-rtl .pika-prev,.pika-next{float:right;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=");*right:0}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block;*display:inline}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:none;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-inrange .pika-button{background:#d5e9f7}.is-startrange .pika-button{color:#fff;background:#6cb31d;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button,.is-outside-current-month .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help}.htCommentCell{position:relative}.htCommentCell:after{content:"";position:absolute;top:0;right:0;border-left:6px solid transparent;border-top:6px solid #000}.htComments{display:none;z-index:1059;position:absolute}.htCommentTextArea{box-shadow:0 1px 3px rgba(0,0,0,.117647),0 1px 2px rgba(0,0,0,.239216);box-sizing:border-box;border:none;border-left:3px solid #ccc;background-color:#fff;width:215px;height:90px;font-size:12px;padding:5px;outline:0!important;-webkit-appearance:none}.htCommentTextArea:focus{box-shadow:0 1px 3px rgba(0,0,0,.117647),0 1px 2px rgba(0,0,0,.239216),inset 0 0 0 1px #5292f7;border-left:3px solid #5292f7}
35 | /*!
36 | * Handsontable ContextMenu
37 | */.htContextMenu:not(.htGhostTable){display:none;position:absolute;z-index:1060}.htContextMenu .ht_clone_corner,.htContextMenu .ht_clone_debug,.htContextMenu .ht_clone_left,.htContextMenu .ht_clone_top{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:#fff;border-width:0;padding:4px 6px 0;cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.htContextMenu table tbody tr td:first-child{border:0}.htContextMenu table tbody tr td.htDimmed{font-style:normal;color:#323232}.htContextMenu table tbody tr td.current,.htContextMenu table tbody tr td.zeroclipboard-is-hover{background:#f3f3f3}.htContextMenu table tbody tr td.htSeparator{border-top:1px solid #e6e6e6;height:0;padding:0;cursor:default}.htContextMenu table tbody tr td.htDisabled{color:#999;cursor:default}.htContextMenu table tbody tr td.htDisabled:hover{background:#fff;color:#999;cursor:default}.htContextMenu table tbody tr.htHidden{display:none}.htContextMenu table tbody tr td .htItemWrapper{margin-left:10px;margin-right:6px}.htContextMenu table tbody tr td div span.selected{margin-top:-2px;position:absolute;left:4px}.htContextMenu .ht_master .wtHolder{overflow:hidden}textarea#HandsontableCopyPaste{position:fixed!important;top:0!important;right:100%!important;overflow:hidden;opacity:0;outline:0 none!important}.htRowHeaders .ht_master.innerBorderLeft~.ht_clone_left td:first-of-type,.htRowHeaders .ht_master.innerBorderLeft~.ht_clone_top_left_corner th:nth-child(2){border-left:0 none}.handsontable.ht__manualColumnMove.after-selection--columns thead th.ht__highlight{cursor:move;cursor:-webkit-grab;cursor:grab}.handsontable.ht__manualColumnMove.on-moving--columns,.handsontable.ht__manualColumnMove.on-moving--columns thead th.ht__highlight{cursor:move;cursor:-webkit-grabbing;cursor:grabbing}.handsontable.ht__manualColumnMove.on-moving--columns .manualColumnResizer{display:none}.handsontable .ht__manualColumnMove--backlight,.handsontable .ht__manualColumnMove--guideline{position:absolute;height:100%;display:none}.handsontable .ht__manualColumnMove--guideline{background:#757575;width:2px;top:0;margin-left:-1px;z-index:105}.handsontable .ht__manualColumnMove--backlight{background:#343434;background:rgba(52,52,52,.25);display:none;z-index:105;pointer-events:none}.handsontable.on-moving--columns .ht__manualColumnMove--backlight,.handsontable.on-moving--columns.show-ui .ht__manualColumnMove--guideline{display:block}.handsontable .wtHider{position:relative}.handsontable.ht__manualRowMove.after-selection--rows tbody th.ht__highlight{cursor:move;cursor:-webkit-grab;cursor:grab}.handsontable.ht__manualRowMove.on-moving--rows,.handsontable.ht__manualRowMove.on-moving--rows tbody th.ht__highlight{cursor:move;cursor:-webkit-grabbing;cursor:grabbing}.handsontable.ht__manualRowMove.on-moving--rows .manualRowResizer{display:none}.handsontable .ht__manualRowMove--backlight,.handsontable .ht__manualRowMove--guideline{position:absolute;width:100%;display:none}.handsontable .ht__manualRowMove--guideline{background:#757575;height:2px;left:0;margin-top:-1px;z-index:105}.handsontable .ht__manualRowMove--backlight{background:#343434;background:rgba(52,52,52,.25);display:none;z-index:105;pointer-events:none}.handsontable.on-moving--rows .ht__manualRowMove--backlight,.handsontable.on-moving--rows.show-ui .ht__manualRowMove--guideline{display:block}.handsontable tbody td[rowspan][class*=area][class*=highlight]:not([class*=fullySelectedMergedCell]):before{opacity:0}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-0]:before,.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-multiple]:before{opacity:.1}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-1]:before{opacity:.2}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-2]:before{opacity:.27}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-3]:before{opacity:.35}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-4]:before{opacity:.41}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-5]:before{opacity:.47}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-6]:before{opacity:.54}.handsontable tbody td[rowspan][class*=area][class*=highlight][class*=fullySelectedMergedCell-7]:before{opacity:.58}
--------------------------------------------------------------------------------
/pyhandsontable/templates/sheet.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
30 |
31 | {{ title }}
32 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/pyhandsontable/templates/sheet.js:
--------------------------------------------------------------------------------
1 | function whatIsIt(object) {
2 | var stringConstructor = "test".constructor;
3 | var arrayConstructor = [].constructor;
4 | var objectConstructor = {}.constructor;
5 |
6 | if (object === null) {
7 | return "null";
8 | }
9 | else if (object === undefined) {
10 | return "undefined";
11 | }
12 | else if (object.constructor === stringConstructor) {
13 | return "String";
14 | }
15 | else if (object.constructor === arrayConstructor) {
16 | return "Array";
17 | }
18 | else if (object.constructor === objectConstructor) {
19 | return "Object";
20 | }
21 | else {
22 | return "don't know";
23 | }
24 | }
25 |
26 | function escapeHTML(unsafeText) {
27 | let div = document.createElement('div');
28 | div.innerText = unsafeText;
29 | return div.innerHTML;
30 | }
31 |
32 | (function(Handsontable){
33 | function customRenderer(hotInstance, td, row, column, prop, value, cellProperties) {
34 | let text;
35 | switch(whatIsIt(value)){
36 | case "Object":
37 | text = '' + JSON.stringify(value, null, 2) + '
';
38 | break;
39 | case "Array":
40 | text = '' + JSON.stringify(value) + '
';
41 | break;
42 | default:
43 | text = '' + escapeHTML(Handsontable.helper.stringify(value)) + '
';
44 | }
45 |
46 | td.innerHTML = text;
47 | return td;
48 | }
49 |
50 | Handsontable.renderers.registerRenderer('jsonRenderer', customRenderer);
51 | })(Handsontable);
52 |
53 | var container = document.getElementById('hotArea');
54 | var actualConfig = {
55 | data: data,
56 | rowHeaders: true,
57 | colHeaders: true,
58 | columns: columns,
59 | manualColumnResize: true,
60 | manualRowResize: true,
61 | renderAllRows: true,
62 | modifyColWidth: (width, col)=>{
63 | if(width > maxColWidth) return maxColWidth;
64 | },
65 | afterRenderer: (td, row, column, prop, value, cellProperties)=>{
66 | td.innerHTML = '';
67 | }
68 | }
69 | Object.assign(actualConfig, config);
70 | actualConfig.colWidths = undefined;
71 |
72 | var hot = new Handsontable(container, actualConfig);
73 |
74 | let colWidths = [];
75 | [...Array(hot.countCols()).keys()].map(i => {
76 | colWidths.push(hot.getColWidth(i));
77 | });
78 |
79 | switch(whatIsIt(config.colWidths)){
80 | case "Array":
81 | config.colWidths.forEach((item, index)=>{
82 | colWidths[index] = item;
83 | });
84 | break;
85 | case "Object":
86 | const colHeaders = hot.getColHeader();
87 | Object.keys(config.colWidths).forEach((item, index)=>{
88 | colWidths[colHeaders.indexOf(item)] = config.colWidths[item];
89 | });
90 | break;
91 | default:
92 | }
93 |
94 | hot.updateSettings({
95 | colWidths: colWidths,
96 | modifyColWidth: ()=>{}
97 | });
--------------------------------------------------------------------------------
/pyproject.lock:
--------------------------------------------------------------------------------
1 | [[package]]
2 | category = "main"
3 | description = "Disable App Nap on OS X 10.9"
4 | name = "appnope"
5 | optional = false
6 | platform = "UNKNOWN"
7 | python-versions = "*"
8 | version = "0.1.0"
9 |
10 | [package.requirements]
11 | platform = "darwin"
12 |
13 | [[package]]
14 | category = "dev"
15 | description = "Atomic file writes."
16 | name = "atomicwrites"
17 | optional = false
18 | platform = "UNKNOWN"
19 | python-versions = "*"
20 | version = "1.1.5"
21 |
22 | [[package]]
23 | category = "dev"
24 | description = "Classes Without Boilerplate"
25 | name = "attrs"
26 | optional = false
27 | platform = "*"
28 | python-versions = "*"
29 | version = "18.1.0"
30 |
31 | [[package]]
32 | category = "main"
33 | description = "Specifications for callback functions passed in to an API"
34 | name = "backcall"
35 | optional = false
36 | platform = "UNKNOWN"
37 | python-versions = "*"
38 | version = "0.1.0"
39 |
40 | [[package]]
41 | category = "main"
42 | description = "An easy safelist-based HTML-sanitizing tool."
43 | name = "bleach"
44 | optional = false
45 | platform = "*"
46 | python-versions = "*"
47 | version = "2.1.3"
48 |
49 | [package.dependencies]
50 | html5lib = ">=0.99999999pre,<1.0b1 || >1.0b1,<1.0b2 || >1.0b2,<1.0b3 || >1.0b3,<1.0b4 || >1.0b4,<1.0b5 || >1.0b5,<1.0b6 || >1.0b6,<1.0b7 || >1.0b7,<1.0b8 || >1.0b8"
51 | six = "*"
52 |
53 | [[package]]
54 | category = "main"
55 | description = "Cross-platform colored terminal text."
56 | name = "colorama"
57 | optional = false
58 | platform = "UNKNOWN"
59 | python-versions = "*"
60 | version = "0.3.9"
61 |
62 | [package.requirements]
63 | platform = "win32"
64 |
65 | [[package]]
66 | category = "main"
67 | description = "Better living through Python with decorators"
68 | name = "decorator"
69 | optional = false
70 | platform = "All"
71 | python-versions = "*"
72 | version = "4.3.0"
73 |
74 | [[package]]
75 | category = "main"
76 | description = "Discover and load entry points from installed packages."
77 | name = "entrypoints"
78 | optional = false
79 | platform = "*"
80 | python-versions = ">=2.7"
81 | version = "0.2.3"
82 |
83 | [[package]]
84 | category = "main"
85 | description = "HTML parser based on the WHATWG HTML specification"
86 | name = "html5lib"
87 | optional = false
88 | platform = "*"
89 | python-versions = "*"
90 | version = "1.0.1"
91 |
92 | [package.dependencies]
93 | six = ">=1.9"
94 | webencodings = "*"
95 |
96 | [[package]]
97 | category = "main"
98 | description = "IPython Kernel for Jupyter"
99 | name = "ipykernel"
100 | optional = false
101 | platform = "Linux"
102 | python-versions = "*"
103 | version = "4.8.2"
104 |
105 | [package.dependencies]
106 | ipython = ">=4.0.0"
107 | jupyter-client = "*"
108 | tornado = ">=4.0"
109 | traitlets = ">=4.1.0"
110 |
111 | [[package]]
112 | category = "main"
113 | description = "IPython: Productive Interactive Computing"
114 | name = "ipython"
115 | optional = false
116 | platform = "Linux"
117 | python-versions = ">=3.3"
118 | version = "6.4.0"
119 |
120 | [package.dependencies]
121 | backcall = "*"
122 | decorator = "*"
123 | jedi = ">=0.10"
124 | pickleshare = "*"
125 | prompt-toolkit = ">=1.0.15,<2.0.0"
126 | pygments = "*"
127 | setuptools = ">=18.5"
128 | simplegeneric = ">0.8"
129 | traitlets = ">=4.2"
130 |
131 | [package.dependencies.appnope]
132 | platform = "darwin"
133 | version = "*"
134 |
135 | [package.dependencies.colorama]
136 | platform = "win32"
137 | version = "*"
138 |
139 | [package.dependencies.pexpect]
140 | platform = "!=win32"
141 | version = "*"
142 |
143 | [package.dependencies.win-unicode-console]
144 | platform = "win32"
145 | python = "<3.6"
146 | version = ">=0.5"
147 |
148 | [[package]]
149 | category = "main"
150 | description = "Vestigial utilities from IPython"
151 | name = "ipython-genutils"
152 | optional = false
153 | platform = "Linux"
154 | python-versions = "*"
155 | version = "0.2.0"
156 |
157 | [[package]]
158 | category = "main"
159 | description = "An autocompletion tool for Python that can be used for text editors."
160 | name = "jedi"
161 | optional = false
162 | platform = "any"
163 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
164 | version = "0.12.1"
165 |
166 | [package.dependencies]
167 | parso = ">=0.3.0"
168 |
169 | [[package]]
170 | category = "main"
171 | description = "A small but fast and easy to use stand-alone template engine written in pure python."
172 | name = "jinja2"
173 | optional = false
174 | platform = "*"
175 | python-versions = "*"
176 | version = "2.10"
177 |
178 | [package.dependencies]
179 | MarkupSafe = ">=0.23"
180 |
181 | [[package]]
182 | category = "main"
183 | description = "An implementation of JSON Schema validation for Python"
184 | name = "jsonschema"
185 | optional = false
186 | platform = "*"
187 | python-versions = "*"
188 | version = "2.6.0"
189 |
190 | [[package]]
191 | category = "main"
192 | description = "Jupyter metapackage. Install all the Jupyter components in one go."
193 | name = "jupyter"
194 | optional = false
195 | platform = "UNKNOWN"
196 | python-versions = "*"
197 | version = "1.0.0"
198 |
199 | [[package]]
200 | category = "main"
201 | description = "Jupyter protocol implementation and client libraries"
202 | name = "jupyter-client"
203 | optional = false
204 | platform = "Linux"
205 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
206 | version = "5.2.3"
207 |
208 | [package.dependencies]
209 | jupyter-core = "*"
210 | python-dateutil = ">=2.1"
211 | pyzmq = ">=13"
212 | tornado = ">=4.1"
213 | traitlets = "*"
214 |
215 | [[package]]
216 | category = "main"
217 | description = "Jupyter core package. A base package on which Jupyter projects rely."
218 | name = "jupyter-core"
219 | optional = false
220 | platform = "*"
221 | python-versions = "*"
222 | version = "4.4.0"
223 |
224 | [package.dependencies]
225 | traitlets = "*"
226 |
227 | [[package]]
228 | category = "main"
229 | description = "Implements a XML/HTML/XHTML Markup safe string for Python"
230 | name = "markupsafe"
231 | optional = false
232 | platform = "UNKNOWN"
233 | python-versions = "*"
234 | version = "1.0"
235 |
236 | [[package]]
237 | category = "main"
238 | description = "The fastest markdown parser in pure Python"
239 | name = "mistune"
240 | optional = false
241 | platform = "any"
242 | python-versions = "*"
243 | version = "0.8.3"
244 |
245 | [[package]]
246 | category = "dev"
247 | description = "More routines for operating on iterables, beyond itertools"
248 | name = "more-itertools"
249 | optional = false
250 | platform = "*"
251 | python-versions = "*"
252 | version = "4.2.0"
253 |
254 | [package.dependencies]
255 | six = ">=1.0.0,<2.0.0"
256 |
257 | [[package]]
258 | category = "main"
259 | description = "Converting Jupyter Notebooks"
260 | name = "nbconvert"
261 | optional = false
262 | platform = "Linux"
263 | python-versions = "*"
264 | version = "5.3.1"
265 |
266 | [package.dependencies]
267 | bleach = "*"
268 | entrypoints = ">=0.2.2"
269 | jinja2 = "*"
270 | jupyter-core = "*"
271 | mistune = ">=0.7.4"
272 | nbformat = ">=4.4"
273 | pandocfilters = ">=1.4.1"
274 | pygments = "*"
275 | testpath = "*"
276 | traitlets = ">=4.2"
277 |
278 | [[package]]
279 | category = "main"
280 | description = "The Jupyter Notebook format"
281 | name = "nbformat"
282 | optional = false
283 | platform = "Linux"
284 | python-versions = "*"
285 | version = "4.4.0"
286 |
287 | [package.dependencies]
288 | ipython-genutils = "*"
289 | jsonschema = ">=2.4,<2.5.0 || >2.5.0"
290 | jupyter-core = "*"
291 | traitlets = ">=4.1"
292 |
293 | [[package]]
294 | category = "main"
295 | description = "A web-based notebook environment for interactive computing"
296 | name = "notebook"
297 | optional = false
298 | platform = "Linux"
299 | python-versions = "*"
300 | version = "5.6.0"
301 |
302 | [package.dependencies]
303 | Send2Trash = "*"
304 | ipykernel = "*"
305 | ipython-genutils = "*"
306 | jinja2 = "*"
307 | jupyter-client = ">=5.2.0"
308 | jupyter-core = ">=4.4.0"
309 | nbconvert = "*"
310 | nbformat = "*"
311 | prometheus-client = "*"
312 | pyzmq = ">=17"
313 | terminado = ">=0.8.1"
314 | tornado = ">=4"
315 | traitlets = ">=4.2.1"
316 |
317 | [[package]]
318 | category = "main"
319 | description = "Utilities for writing pandoc filters in python"
320 | name = "pandocfilters"
321 | optional = false
322 | platform = "*"
323 | python-versions = "*"
324 | version = "1.4.2"
325 |
326 | [[package]]
327 | category = "main"
328 | description = "A Python Parser"
329 | name = "parso"
330 | optional = false
331 | platform = "any"
332 | python-versions = "*"
333 | version = "0.3.1"
334 |
335 | [[package]]
336 | category = "main"
337 | description = "Pexpect allows easy control of interactive console applications."
338 | name = "pexpect"
339 | optional = false
340 | platform = "UNIX"
341 | python-versions = "*"
342 | version = "4.6.0"
343 |
344 | [package.dependencies]
345 | ptyprocess = ">=0.5"
346 |
347 | [package.requirements]
348 | platform = "!=win32"
349 |
350 | [[package]]
351 | category = "main"
352 | description = "Tiny 'shelve'-like database with concurrency support"
353 | name = "pickleshare"
354 | optional = false
355 | platform = "*"
356 | python-versions = "*"
357 | version = "0.7.4"
358 |
359 | [[package]]
360 | category = "dev"
361 | description = "plugin and hook calling mechanisms for python"
362 | name = "pluggy"
363 | optional = false
364 | platform = "unix"
365 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
366 | version = "0.6.0"
367 |
368 | [[package]]
369 | category = "main"
370 | description = "Python client for the Prometheus monitoring system."
371 | name = "prometheus-client"
372 | optional = false
373 | platform = "*"
374 | python-versions = "*"
375 | version = "0.3.0"
376 |
377 | [[package]]
378 | category = "main"
379 | description = "Library for building powerful interactive command lines in Python"
380 | name = "prompt-toolkit"
381 | optional = false
382 | platform = "*"
383 | python-versions = "*"
384 | version = "1.0.15"
385 |
386 | [package.dependencies]
387 | six = ">=1.9.0"
388 | wcwidth = "*"
389 |
390 | [[package]]
391 | category = "main"
392 | description = "Run a subprocess in a pseudo terminal"
393 | name = "ptyprocess"
394 | optional = false
395 | platform = "*"
396 | python-versions = "*"
397 | version = "0.6.0"
398 |
399 | [[package]]
400 | category = "dev"
401 | description = "library with cross-python path, ini-parsing, io, code, log facilities"
402 | name = "py"
403 | optional = false
404 | platform = "unix"
405 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
406 | version = "1.5.4"
407 |
408 | [[package]]
409 | category = "main"
410 | description = "Pygments is a syntax highlighting package written in Python."
411 | name = "pygments"
412 | optional = false
413 | platform = "any"
414 | python-versions = "*"
415 | version = "2.2.0"
416 |
417 | [[package]]
418 | category = "dev"
419 | description = "pytest: simple powerful testing with Python"
420 | name = "pytest"
421 | optional = false
422 | platform = "unix"
423 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
424 | version = "3.6.3"
425 |
426 | [package.dependencies]
427 | atomicwrites = ">=1.0"
428 | attrs = ">=17.4.0"
429 | more-itertools = ">=4.0.0"
430 | pluggy = ">=0.5,<0.7"
431 | py = ">=1.5.0"
432 | setuptools = "*"
433 | six = ">=1.10.0"
434 |
435 | [package.dependencies.colorama]
436 | platform = "win32"
437 | version = "*"
438 |
439 | [[package]]
440 | category = "main"
441 | description = "Extensions to the standard Python datetime module"
442 | name = "python-dateutil"
443 | optional = false
444 | platform = "*"
445 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
446 | version = "2.7.3"
447 |
448 | [package.dependencies]
449 | six = ">=1.5"
450 |
451 | [[package]]
452 | category = "main"
453 | description = "Python bindings for the winpty library"
454 | name = "pywinpty"
455 | optional = false
456 | platform = "*"
457 | python-versions = "*"
458 | version = "0.5.4"
459 |
460 | [[package]]
461 | category = "main"
462 | description = "Python bindings for 0MQ"
463 | name = "pyzmq"
464 | optional = false
465 | platform = "*"
466 | python-versions = ">=2.7,!=3.0*,!=3.1*,!=3.2*"
467 | version = "17.1.0"
468 |
469 | [[package]]
470 | category = "main"
471 | description = "Send file to trash natively under Mac OS X, Windows and Linux."
472 | name = "send2trash"
473 | optional = false
474 | platform = "*"
475 | python-versions = "*"
476 | version = "1.5.0"
477 |
478 | [[package]]
479 | category = "main"
480 | description = "Simple generic functions (similar to Python's own len(), pickle.dump(), etc.)"
481 | name = "simplegeneric"
482 | optional = false
483 | platform = "UNKNOWN"
484 | python-versions = "*"
485 | version = "0.8.1"
486 |
487 | [[package]]
488 | category = "main"
489 | description = "Python 2 and 3 compatibility utilities"
490 | name = "six"
491 | optional = false
492 | platform = "*"
493 | python-versions = "*"
494 | version = "1.11.0"
495 |
496 | [[package]]
497 | category = "main"
498 | description = "Terminals served to xterm.js using Tornado websockets"
499 | name = "terminado"
500 | optional = false
501 | platform = "*"
502 | python-versions = "*"
503 | version = "0.8.1"
504 |
505 | [package.dependencies]
506 | ptyprocess = "*"
507 | pywinpty = ">=0.5"
508 | tornado = ">=4"
509 |
510 | [[package]]
511 | category = "main"
512 | description = "Test utilities for code working with files and commands"
513 | name = "testpath"
514 | optional = false
515 | platform = "*"
516 | python-versions = "*"
517 | version = "0.3.1"
518 |
519 | [[package]]
520 | category = "main"
521 | description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
522 | name = "tornado"
523 | optional = false
524 | platform = "*"
525 | python-versions = ">= 2.7, !=3.0.*, !=3.1.*, !=3.2.*, != 3.3.*"
526 | version = "5.1"
527 |
528 | [[package]]
529 | category = "main"
530 | description = "Traitlets Python config system"
531 | name = "traitlets"
532 | optional = false
533 | platform = "Linux,Mac OS X,Windows"
534 | python-versions = "*"
535 | version = "4.3.2"
536 |
537 | [package.dependencies]
538 | decorator = "*"
539 | ipython-genutils = "*"
540 | six = "*"
541 |
542 | [[package]]
543 | category = "main"
544 | description = "Measures number of Terminal column cells of wide-character codes"
545 | name = "wcwidth"
546 | optional = false
547 | platform = "UNKNOWN"
548 | python-versions = "*"
549 | version = "0.1.7"
550 |
551 | [[package]]
552 | category = "main"
553 | description = "Character encoding aliases for legacy web content"
554 | name = "webencodings"
555 | optional = false
556 | platform = "*"
557 | python-versions = "*"
558 | version = "0.5.1"
559 |
560 | [[package]]
561 | category = "main"
562 | description = "Enable Unicode input and display when running Python from Windows console."
563 | name = "win-unicode-console"
564 | optional = false
565 | platform = "UNKNOWN"
566 | python-versions = "*"
567 | version = "0.5"
568 |
569 | [package.requirements]
570 | platform = "win32"
571 | python = "<3.6"
572 |
573 | [metadata]
574 | content-hash = "160320ef4bea25f480846c0c0cdc0023c1403000a5e931df647ccf2cb44e2953"
575 | platform = "*"
576 | python-versions = ">=3.5"
577 |
578 | [metadata.hashes]
579 | appnope = ["5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", "8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"]
580 | atomicwrites = ["240831ea22da9ab882b551b31d4225591e5e447a68c5e188db5b89ca1d487585", "a24da68318b08ac9c9c45029f4a10371ab5b20e4226738e150e6e7c571630ae6"]
581 | attrs = ["4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265", "e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b"]
582 | backcall = ["38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", "bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"]
583 | bleach = ["b8fa79e91f96c2c2cd9fd1f9eda906efb1b88b483048978ba62fef680e962b34", "eb7386f632349d10d9ce9d4a838b134d4731571851149f9cc2c05a9a837a9a44"]
584 | colorama = ["463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda", "48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"]
585 | decorator = ["2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82", "c39efa13fbdeb4506c476c9b3babf6a718da943dab7811c206005a4a956c080c"]
586 | entrypoints = ["10ad569bb245e7e2ba425285b9fa3e8178a0dc92fc53b1e1c553805e15a8825b", "d2d587dde06f99545fb13a383d2cd336a8ff1f359c5839ce3a64c917d10c029f"]
587 | html5lib = ["20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3", "66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736"]
588 | ipykernel = ["395f020610e33ffa0b0c9c0cd1a1d927d51ab9aa9f30a7ae36bb0c908a33e89c", "935941dba29d856eee34b8b5261d971bd5012547239ed73ddfff099143748c37", "c091449dd0fad7710ddd9c4a06e8b9e15277da306590bc07a3a1afa6b4453c8f"]
589 | ipython = ["a0c96853549b246991046f32d19db7140f5b1a644cc31f0dc1edc86713b7676f", "eca537aa61592aca2fef4adea12af8e42f5c335004dfa80c78caf80e8b525e5c"]
590 | ipython-genutils = ["72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", "eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"]
591 | jedi = ["b409ed0f6913a701ed474a614a3bb46e6953639033e31f769ca7581da5bd1ec1", "c254b135fb39ad76e78d4d8f92765ebc9bf92cbc76f49e97ade1d5f5121e1f6f"]
592 | jinja2 = ["74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", "f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"]
593 | jsonschema = ["000e68abd33c972a5248544925a0cae7d1125f9bf6c58280d37546b946769a08", "6ff5f3180870836cae40f06fa10419f557208175f13ad7bc26caa77beb1f6e02"]
594 | jupyter = ["3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7", "5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78", "d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"]
595 | jupyter-client = ["27befcf0446b01e29853014d6a902dd101ad7d7f94e2252b1adca17c3466b761", "59e6d791e22a8002ad0e80b78c6fd6deecab4f9e1b1aa1a22f4213de271b29ea"]
596 | jupyter-core = ["927d713ffa616ea11972534411544589976b2493fc7e09ad946e010aa7eb9970", "ba70754aa680300306c699790128f6fbd8c306ee5927976cbe48adacf240c0b7"]
597 | markupsafe = ["a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"]
598 | mistune = ["b4c512ce2fc99e5a62eb95a4aba4b73e5f90264115c40b70a21e1f7d4e0eac91", "bc10c33bfdcaa4e749b779f62f60d6e12f8215c46a292d05e486b869ae306619"]
599 | more-itertools = ["2b6b9893337bfd9166bee6a62c2b0c9fe7735dcf85948b387ec8cba30e85d8e8", "6703844a52d3588f951883005efcf555e49566a48afd4db4e965d69b883980d3", "a18d870ef2ffca2b8463c0070ad17b5978056f403fb64e3f15fe62a52db21cc0"]
600 | nbconvert = ["12b1a4671d4463ab73af6e4cbcc965b62254e05d182cd54995dda0d0ef9e2db9", "260d390b989a647575b8ecae2cd06a9eaead10d396733d6e50185d5ebd08996e"]
601 | nbformat = ["b9a0dbdbd45bb034f4f8893cafd6f652ea08c8c1674ba83f2dc55d3955743b0b", "f7494ef0df60766b7cabe0a3651556345a963b74dbc16bc7c18479041170d402"]
602 | notebook = ["66dd59e76e755584ae9450eb015c39f55d4bb1d8ec68f2c694d2b3cba7bf5c7e", "e2c8e931cc19db4f8c63e6a396efbc13a228b2cb5b2919df011b946f28239a08"]
603 | pandocfilters = ["b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"]
604 | parso = ["35704a43a3c113cce4de228ddb39aab374b8004f4f2407d070b6a2ca784ce8a2", "895c63e93b94ac1e1690f5fdd40b65f07c8171e3e53cbd7793b5b96c0e0a7f24"]
605 | pexpect = ["2a8e88259839571d1251d278476f3eec5db26deb73a70be5ed5dc5435e418aba", "3fbd41d4caf27fa4a377bfd16fef87271099463e6fa73e92a52f92dfee5d425b"]
606 | pickleshare = ["84a9257227dfdd6fe1b4be1319096c20eb85ff1e82c7932f36efccfe1b09737b", "c9a2541f25aeabc070f12f452e1f2a8eae2abd51e1cd19e8430402bdf4c1d8b5"]
607 | pluggy = ["7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", "d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", "e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5"]
608 | prometheus-client = ["69494dc1ac967c0f626c8193e439755c2b95dd4ed22ef31c277601778a50c7ff"]
609 | prompt-toolkit = ["1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381", "3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4", "858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917"]
610 | ptyprocess = ["923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", "d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"]
611 | py = ["3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", "e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e"]
612 | pygments = ["78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d", "dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"]
613 | pytest = ["0453c8676c2bee6feb0434748b068d5510273a916295fd61d306c4f22fbfd752", "4b208614ae6d98195430ad6bde03641c78553acee7c83cec2e85d613c0cd383d"]
614 | python-dateutil = ["1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", "e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8"]
615 | pywinpty = ["349eef36414b038426e65d96ecccfa581c437562cc164fb4faffe6f46963bc80", "4617637c38ae9099a99f73d8dbeb9c752743693bd1dca6ea3b1d520a7248ebf3", "4ee8193b19d77ab59097a000a2c52b36e768e92263812e0c0b40306be8927fb4", "4f6c850db79dd19b1d842d81a8c08fd7efad5e160a1effbba10ba738a5a35cb2", "4fd720b20bb69f1b7ca2060e84503ae843972fcb006ae6e8ddd6ab212fe8911c", "79f2b4584111e36826e587d33eb4e7416a12ae1d6c094cb554e873c5c162fa5f", "87ae1a2301fbce7a3005dac7cdf8ce8a4162f05130348234b87caef260771e96"]
616 | pyzmq = ["096b72e48dc4fb6afac4dc862626b103287176be7c0f49b52782689eac4bf376", "1c0d469837c54df4b3b8424c79f102a2a4ccc7e1e7f8816fcdcf39c1e6406b19", "2199f753a230e26aec5238b0518b036780708a4c887d4944519681a920b9dee4", "22402d2a55dcc5973b1356be12dbc4417350fcc85a6da3af2984271e769a28f4", "4166c2e45b5d43bc1da49a7f8518c2ced11227fb69b35405940442b92b0b0c34", "488ab43a9c4a710264987e7efe5d53384858281bd6540db0a47e7bb6c3bf7ec5", "8d757eaf5eb3b27ab449343e55b8e8f442a3de67ccdfca893cefe8964d44a147", "8e576262221c7fbee894cf105eb975f1385fc91988ce6120cdb2305195e7a9f6", "90b38559b33f544ebaa35fcb8d4091cb35c689a3cfe92e584e36c746f648c12b", "911f457a0b5c0e0c857a71bd2abbb96d15c695a11cf61caa43059143ed01bb6e", "941c9676bc2f3dbab528a4cd42a9dd80310156ed6014276f16288f25c9ff4da2", "965d50febc5402e7fb93c432155463b4184a79bec040cdeb3b006b278b3a544f", "98fe34bbbe5a516e75ac16f1ea585d9c1dda2067b6c9f4da174add6c952883b6", "9dc60c4a8299aa77082493231045d15b58c7875cb9f3dbee6e11a86356bd9e24", "a3d1c56387332063a5492c186fb504a7b6dfbdf6f0ce0a7388fed722998e3b0f", "a9660113ff4c52160f734704af8d351326cc6eabf1dbd135cf02c0ded02e1d9d", "b097f32a1ee00e0b2aa9776e0112a73655484d2e7c0634757c84c036c8be0706", "bcd81ab868e916fc22172667e528211b21e2dcab9af2e9fb3ee631d3eb946893", "bd1c9cbb6d1032a61a8ab0e77b1c83caa7b04e77a6736ff23d213de6bde92622", "cfe8d245bd62b3f87e120029f5a83f47055d3bb2d2b7f91566dd43487dedd6e3", "d74052450985befe7d983abb1daab6112b5cb78f1258731afe04c55dbb504739", "df65629511d6037045b2b4d87b17b0a984d7ae6af44e0d87c350c93e6685d746", "e724a5117044490cf0f55b5025bba4b909de0be4f47f6a48ad7c24d6a8e7e48c", "fafcb5be16c0012ada037b8eaf63d5b25d421680072eeb6df4a2d90599d962e6", "fdced6cf08aaa5b0dacfa4562e518ffb562bb09a90483f920cf6c4ecabd3f379"]
617 | send2trash = ["60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2", "f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"]
618 | simplegeneric = ["dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173"]
619 | six = ["70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", "832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"]
620 | terminado = ["55abf9ade563b8f9be1f34e4233c7b7bde726059947a593322e8a553cc4c067a", "65011551baff97f5414c67018e908110693143cfbaeb16831b743fe7cad8b927"]
621 | testpath = ["039fa6a6c9fd3488f8336d23aebbfead5fa602c4a47d49d83845f55a595ec1b4", "0d5337839c788da5900df70f8e01015aec141aa3fe7936cb0d0a2953f7ac7609"]
622 | tornado = ["1c0816fc32b7d31b98781bd8ebc7a9726d7dce67407dc353a2e66e697e138448", "4f66a2172cb947387193ca4c2c3e19131f1c70fa8be470ddbbd9317fd0801582", "5327ba1a6c694e0149e7d9126426b3704b1d9d520852a3e4aa9fc8fe989e4046", "6a7e8657618268bb007646b9eae7661d0b57f13efc94faa33cd2588eae5912c9", "a9b14804783a1d77c0bd6c66f7a9b1196cbddfbdf8bceb64683c5ae60bd1ec6f", "c58757e37c4a3172949c99099d4d5106e4d7b63aa0617f9bb24bfbff712c7866", "d8984742ce86c0855cccecd5c6f54a9f7532c983947cff06f3a0e2115b47f85c"]
623 | traitlets = ["9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", "c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9"]
624 | wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"]
625 | webencodings = ["a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", "b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"]
626 | win-unicode-console = ["d4142d4d56d46f449d6f00536a73625a871cba040f0bc1a2e305a04578f07d1e"]
627 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "pyhandsontable"
3 | version = "0.3"
4 | description = "View a list of dictionaries or a 2-D array, in HandsOnTable, in Jupyter Notebook."
5 | authors = ["Pacharapol Withayasakpunt "]
6 | license = "MIT"
7 | readme = "README.md"
8 | repository = "https://github.com/patarapolw/pyhandsontable"
9 | homepage = "https://github.com/patarapolw/pyhandsontable"
10 | keywords = ['handsontable']
11 |
12 | [tool.poetry.dependencies]
13 | python = ">=3.5"
14 | jinja2 = "^2.10"
15 | jupyter = "^1.0"
16 | notebook = "^5.6"
17 |
18 | [tool.poetry.dev-dependencies]
19 | pytest = "^3.6"
20 |
--------------------------------------------------------------------------------
/screenshots/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patarapolw/pyhandsontable/40a6886f3ca1eec9e7b54aebd354da152ab63940/screenshots/0.png
--------------------------------------------------------------------------------
/screenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patarapolw/pyhandsontable/40a6886f3ca1eec9e7b54aebd354da152ab63940/screenshots/1.png
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patarapolw/pyhandsontable/40a6886f3ca1eec9e7b54aebd354da152ab63940/tests/__init__.py
--------------------------------------------------------------------------------
/tests/output/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/tests/test_generate.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from pathlib import Path
3 |
4 | from pyhandsontable import generate_html
5 |
6 |
7 | @pytest.mark.parametrize('kwargs', [
8 | {'data': [[1, 2, 3], [4, 5, 6]]},
9 | {'data': [[False]]},
10 | {'data': [[1, 2, 3], [4, 5, 6]], 'config': {'rowHeaders': False}},
11 | {'data': [[1, 2, 3], [4, 5, 6]], 'config': {'colHeaders': False}}
12 | ])
13 | def test_generate(kwargs, request):
14 | with Path('tests/output').joinpath(request.node.name + '.html').open('w') as f:
15 | f.write(generate_html(**kwargs))
16 |
--------------------------------------------------------------------------------