From 2d28641fac7c737525add47e0932c99ef2807acc Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Sun, 28 May 2023 04:44:41 +0000 Subject: [PATCH 01/11] support panel 1.0 --- .github/workflows/tests.yaml | 10 +- DEVELOPER_GUIDE.md | 2 +- examples/reference/JSMEEditor.ipynb | 7 +- examples/reference/NGLViewer.ipynb | 12 +- examples/reference/PDBe_MolStar.ipynb | 540 +----------- examples/reference/Py3DMol.ipynb | 3 +- pyproject.toml | 6 +- src/panel_chemistry/__init__.py | 2 +- .../bokeh_extensions/jsme_editor.py | 4 +- .../bokeh_extensions/jsme_editor.ts | 2 +- .../bokeh_extensions/layout.ts | 97 +++ .../bokeh_extensions/ngl_viewer.py | 3 +- .../bokeh_extensions/ngl_viewer.ts | 10 +- src/panel_chemistry/package-lock.json | 772 +----------------- src/panel_chemistry/package.json | 4 +- src/panel_chemistry/pane/ngl_viewer.py | 6 +- src/panel_chemistry/pane/pdbe_molstar.py | 7 +- src/panel_chemistry/widgets/jsme_editor.py | 10 +- tests/conftest.py | 16 + tests/pane/test_ngl_viewer.py | 21 +- tests/pane/test_pdbe_molstar_viewer.py | 15 +- tests/tests/test_jsme_editor.py | 14 +- 22 files changed, 207 insertions(+), 1356 deletions(-) create mode 100644 src/panel_chemistry/bokeh_extensions/layout.ts create mode 100644 tests/conftest.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 122fc11..b45f102 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -15,20 +15,20 @@ jobs: strategy: matrix: os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] - python-version: [3.7, 3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10', '3.11'] exclude: - - os: windows-latest - python-version: 3.8 - os: windows-latest python-version: 3.9 - os: windows-latest python-version: '3.10' - - os: macos-latest - python-version: 3.8 + - os: windows-latest + python-version: '3.11' - os: macos-latest python-version: 3.9 - os: macos-latest python-version: '3.10' + - os: macos-latest + python-version: '3.11' env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index c4104d6..2981169 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -18,7 +18,7 @@ Below we describe how to install and use this project for development. To install for development you will need to create and activate a virtual environment ```bash -conda create --name panel-chemistry python=3.9 nodejs +conda create --name panel-chemistry python=3.10 nodejs conda activate panel-chemistry ``` diff --git a/examples/reference/JSMEEditor.ipynb b/examples/reference/JSMEEditor.ipynb index 37e1691..37ba27c 100644 --- a/examples/reference/JSMEEditor.ipynb +++ b/examples/reference/JSMEEditor.ipynb @@ -161,9 +161,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python [conda env:root] *", "language": "python", - "name": "python3" + "name": "conda-root-py" }, "language_info": { "codemirror_mode": { @@ -174,8 +174,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.4" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/examples/reference/NGLViewer.ipynb b/examples/reference/NGLViewer.ipynb index a376afb..793f6ce 100644 --- a/examples/reference/NGLViewer.ipynb +++ b/examples/reference/NGLViewer.ipynb @@ -83,14 +83,7 @@ "cell_type": "code", "execution_count": null, "id": "6e35c77b", - "metadata": { - "jupyter": { - "outputs_hidden": false - }, - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "file_input = pn.widgets.FileInput(accept=','.join('.' + s for s in EXTENSIONS[1:]))\n", @@ -196,8 +189,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.4" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/examples/reference/PDBe_MolStar.ipynb b/examples/reference/PDBe_MolStar.ipynb index 34fefc7..cae9558 100644 --- a/examples/reference/PDBe_MolStar.ipynb +++ b/examples/reference/PDBe_MolStar.ipynb @@ -26,424 +26,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "\n", - "(function(root) {\n", - " function now() {\n", - " return new Date();\n", - " }\n", - "\n", - " var force = true;\n", - "\n", - " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n", - " root._bokeh_onload_callbacks = [];\n", - " root._bokeh_is_loading = undefined;\n", - " }\n", - "\n", - " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", - " root._bokeh_timeout = Date.now() + 5000;\n", - " root._bokeh_failed_load = false;\n", - " }\n", - "\n", - " function run_callbacks() {\n", - " try {\n", - " root._bokeh_onload_callbacks.forEach(function(callback) {\n", - " if (callback != null)\n", - " callback();\n", - " });\n", - " } finally {\n", - " delete root._bokeh_onload_callbacks\n", - " }\n", - " console.debug(\"Bokeh: all callbacks have finished\");\n", - " }\n", - "\n", - " function load_libs(css_urls, js_urls, js_modules, callback) {\n", - " if (css_urls == null) css_urls = [];\n", - " if (js_urls == null) js_urls = [];\n", - " if (js_modules == null) js_modules = [];\n", - "\n", - " root._bokeh_onload_callbacks.push(callback);\n", - " if (root._bokeh_is_loading > 0) {\n", - " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", - " return null;\n", - " }\n", - " if (js_urls.length === 0 && js_modules.length === 0) {\n", - " run_callbacks();\n", - " return null;\n", - " }\n", - " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", - "\n", - " function on_load() {\n", - " root._bokeh_is_loading--;\n", - " if (root._bokeh_is_loading === 0) {\n", - " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", - " run_callbacks()\n", - " }\n", - " }\n", - "\n", - " function on_error() {\n", - " console.error(\"failed to load \" + url);\n", - " }\n", - "\n", - " for (var i = 0; i < css_urls.length; i++) {\n", - " var url = css_urls[i];\n", - " const element = document.createElement(\"link\");\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.rel = \"stylesheet\";\n", - " element.type = \"text/css\";\n", - " element.href = url;\n", - " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", - " document.body.appendChild(element);\n", - " }\n", - "\n", - " var skip = [];\n", - " if (window.requirejs) {\n", - " window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n", - " \n", - " root._bokeh_is_loading = css_urls.length + 0;\n", - " } else {\n", - " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n", - " }\n", - " for (var i = 0; i < js_urls.length; i++) {\n", - " var url = js_urls[i];\n", - " if (skip.indexOf(url) >= 0) {\n", - "\tif (!window.requirejs) {\n", - "\t on_load();\n", - "\t}\n", - "\tcontinue;\n", - " }\n", - " var element = document.createElement('script');\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.src = url;\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " document.head.appendChild(element);\n", - " }\n", - " for (var i = 0; i < js_modules.length; i++) {\n", - " var url = js_modules[i];\n", - " if (skip.indexOf(url) >= 0) {\n", - "\tif (!window.requirejs) {\n", - "\t on_load();\n", - "\t}\n", - "\tcontinue;\n", - " }\n", - " var element = document.createElement('script');\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.src = url;\n", - " element.type = \"module\";\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " document.head.appendChild(element);\n", - " }\n", - " if (!js_urls.length && !js_modules.length) {\n", - " on_load()\n", - " }\n", - " };\n", - "\n", - " function inject_raw_css(css) {\n", - " const element = document.createElement(\"style\");\n", - " element.appendChild(document.createTextNode(css));\n", - " document.body.appendChild(element);\n", - " }\n", - "\n", - " var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js\", \"https://www.ebi.ac.uk/pdbe/pdb-component-library/js/pdbe-molstar-plugin-1.2.1.js\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/panel.min.js\"];\n", - " var js_modules = [];\n", - " var css_urls = [\"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/loading.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/widgets.css\"];\n", - " var inline_js = [\n", - " function(Bokeh) {\n", - " inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\");\\n max-height: 400px;\\n }\\n \");\n", - " },\n", - " function(Bokeh) {\n", - " Bokeh.set_log_level(\"info\");\n", - " },\n", - " function(Bokeh) {} // ensure no trailing comma for IE\n", - " ];\n", - "\n", - " function run_inline_js() {\n", - " if ((root.Bokeh !== undefined) || (force === true)) {\n", - " for (var i = 0; i < inline_js.length; i++) {\n", - " inline_js[i].call(root, root.Bokeh);\n", - " }} else if (Date.now() < root._bokeh_timeout) {\n", - " setTimeout(run_inline_js, 100);\n", - " } else if (!root._bokeh_failed_load) {\n", - " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", - " root._bokeh_failed_load = true;\n", - " }\n", - " }\n", - "\n", - " if (root._bokeh_is_loading === 0) {\n", - " console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", - " run_inline_js();\n", - " } else {\n", - " load_libs(css_urls, js_urls, js_modules, function() {\n", - " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", - " run_inline_js();\n", - " });\n", - " }\n", - "}(window));" - ], - "application/vnd.holoviews_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n \n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length;\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) >= 0) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) >= 0) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js\", \"https://www.ebi.ac.uk/pdbe/pdb-component-library/js/pdbe-molstar-plugin-1.2.1.js\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/panel.min.js\"];\n var js_modules = [];\n var css_urls = [\"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/alerts.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/card.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/dataframe.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/json.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/loading.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/markdown.css\", \"https://unpkg.com/@holoviz/panel@0.12.6/dist/css/widgets.css\"];\n var inline_js = [\n function(Bokeh) {\n inject_raw_css(\"\\n .bk.pn-loading.arcs:before {\\n background-image: url(\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiBub25lOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4gIDxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjMyIiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZT0iI2MzYzNjMyIgc3Ryb2tlLWRhc2hhcnJheT0iNTAuMjY1NDgyNDU3NDM2NjkgNTAuMjY1NDgyNDU3NDM2NjkiIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+ICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZHVyPSIxcyIga2V5VGltZXM9IjA7MSIgdmFsdWVzPSIwIDUwIDUwOzM2MCA1MCA1MCI+PC9hbmltYXRlVHJhbnNmb3JtPiAgPC9jaXJjbGU+PC9zdmc+\\\");\\n max-height: 400px;\\n }\\n \");\n },\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n function(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, js_modules, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "\n", - "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", - " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", - "}\n", - "\n", - "\n", - " function JupyterCommManager() {\n", - " }\n", - "\n", - " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", - " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", - " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", - " comm_manager.register_target(comm_id, function(comm) {\n", - " comm.on_msg(msg_handler);\n", - " });\n", - " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", - " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", - " comm.onMsg = msg_handler;\n", - " });\n", - " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", - " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", - " var messages = comm.messages[Symbol.asyncIterator]();\n", - " function processIteratorResult(result) {\n", - " var message = result.value;\n", - " console.log(message)\n", - " var content = {data: message.data, comm_id};\n", - " var buffers = []\n", - " for (var buffer of message.buffers || []) {\n", - " buffers.push(new DataView(buffer))\n", - " }\n", - " var metadata = message.metadata || {};\n", - " var msg = {content, buffers, metadata}\n", - " msg_handler(msg);\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " return messages.next().then(processIteratorResult);\n", - " })\n", - " }\n", - " }\n", - "\n", - " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", - " if (comm_id in window.PyViz.comms) {\n", - " return window.PyViz.comms[comm_id];\n", - " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", - " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", - " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", - " if (msg_handler) {\n", - " comm.on_msg(msg_handler);\n", - " }\n", - " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", - " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", - " comm.open();\n", - " if (msg_handler) {\n", - " comm.onMsg = msg_handler;\n", - " }\n", - " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", - " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", - " comm_promise.then((comm) => {\n", - " window.PyViz.comms[comm_id] = comm;\n", - " if (msg_handler) {\n", - " var messages = comm.messages[Symbol.asyncIterator]();\n", - " function processIteratorResult(result) {\n", - " var message = result.value;\n", - " var content = {data: message.data};\n", - " var metadata = message.metadata || {comm_id};\n", - " var msg = {content, metadata}\n", - " msg_handler(msg);\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " }) \n", - " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", - " return comm_promise.then((comm) => {\n", - " comm.send(data, metadata, buffers, disposeOnDone);\n", - " });\n", - " };\n", - " var comm = {\n", - " send: sendClosure\n", - " };\n", - " }\n", - " window.PyViz.comms[comm_id] = comm;\n", - " return comm;\n", - " }\n", - " window.PyViz.comm_manager = new JupyterCommManager();\n", - " \n", - "\n", - "\n", - "var JS_MIME_TYPE = 'application/javascript';\n", - "var HTML_MIME_TYPE = 'text/html';\n", - "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", - "var CLASS_NAME = 'output';\n", - "\n", - "/**\n", - " * Render data to the DOM node\n", - " */\n", - "function render(props, node) {\n", - " var div = document.createElement(\"div\");\n", - " var script = document.createElement(\"script\");\n", - " node.appendChild(div);\n", - " node.appendChild(script);\n", - "}\n", - "\n", - "/**\n", - " * Handle when a new output is added\n", - " */\n", - "function handle_add_output(event, handle) {\n", - " var output_area = handle.output_area;\n", - " var output = handle.output;\n", - " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", - " return\n", - " }\n", - " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", - " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", - " if (id !== undefined) {\n", - " var nchildren = toinsert.length;\n", - " var html_node = toinsert[nchildren-1].children[0];\n", - " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", - " var scripts = [];\n", - " var nodelist = html_node.querySelectorAll(\"script\");\n", - " for (var i in nodelist) {\n", - " if (nodelist.hasOwnProperty(i)) {\n", - " scripts.push(nodelist[i])\n", - " }\n", - " }\n", - "\n", - " scripts.forEach( function (oldScript) {\n", - " var newScript = document.createElement(\"script\");\n", - " var attrs = [];\n", - " var nodemap = oldScript.attributes;\n", - " for (var j in nodemap) {\n", - " if (nodemap.hasOwnProperty(j)) {\n", - " attrs.push(nodemap[j])\n", - " }\n", - " }\n", - " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", - " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", - " oldScript.parentNode.replaceChild(newScript, oldScript);\n", - " });\n", - " if (JS_MIME_TYPE in output.data) {\n", - " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", - " }\n", - " output_area._hv_plot_id = id;\n", - " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", - " window.PyViz.plot_index[id] = Bokeh.index[id];\n", - " } else {\n", - " window.PyViz.plot_index[id] = null;\n", - " }\n", - " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", - " var bk_div = document.createElement(\"div\");\n", - " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", - " var script_attrs = bk_div.children[0].attributes;\n", - " for (var i = 0; i < script_attrs.length; i++) {\n", - " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", - " }\n", - " // store reference to server id on output_area\n", - " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", - " }\n", - "}\n", - "\n", - "/**\n", - " * Handle when an output is cleared or removed\n", - " */\n", - "function handle_clear_output(event, handle) {\n", - " var id = handle.cell.output_area._hv_plot_id;\n", - " var server_id = handle.cell.output_area._bokeh_server_id;\n", - " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", - " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", - " if (server_id !== null) {\n", - " comm.send({event_type: 'server_delete', 'id': server_id});\n", - " return;\n", - " } else if (comm !== null) {\n", - " comm.send({event_type: 'delete', 'id': id});\n", - " }\n", - " delete PyViz.plot_index[id];\n", - " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", - " var doc = window.Bokeh.index[id].model.document\n", - " doc.clear();\n", - " const i = window.Bokeh.documents.indexOf(doc);\n", - " if (i > -1) {\n", - " window.Bokeh.documents.splice(i, 1);\n", - " }\n", - " }\n", - "}\n", - "\n", - "/**\n", - " * Handle kernel restart event\n", - " */\n", - "function handle_kernel_cleanup(event, handle) {\n", - " delete PyViz.comms[\"hv-extension-comm\"];\n", - " window.PyViz.plot_index = {}\n", - "}\n", - "\n", - "/**\n", - " * Handle update_display_data messages\n", - " */\n", - "function handle_update_output(event, handle) {\n", - " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", - " handle_add_output(event, handle)\n", - "}\n", - "\n", - "function register_renderer(events, OutputArea) {\n", - " function append_mime(data, metadata, element) {\n", - " // create a DOM node to render to\n", - " var toinsert = this.create_output_subarea(\n", - " metadata,\n", - " CLASS_NAME,\n", - " EXEC_MIME_TYPE\n", - " );\n", - " this.keyboard_manager.register_events(toinsert);\n", - " // Render to node\n", - " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", - " render(props, toinsert[0]);\n", - " element.append(toinsert);\n", - " return toinsert\n", - " }\n", - "\n", - " events.on('output_added.OutputArea', handle_add_output);\n", - " events.on('output_updated.OutputArea', handle_update_output);\n", - " events.on('clear_output.CodeCell', handle_clear_output);\n", - " events.on('delete.Cell', handle_clear_output);\n", - " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", - "\n", - " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", - " safe: true,\n", - " index: 0\n", - " });\n", - "}\n", - "\n", - "if (window.Jupyter !== undefined) {\n", - " try {\n", - " var events = require('base/js/events');\n", - " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", - " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", - " register_renderer(events, OutputArea);\n", - " }\n", - " } catch(err) {\n", - " }\n", - "}\n" - ], - "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "from panel_chemistry.pane import PDBeMolStar\n", "import param\n", @@ -462,64 +47,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "PDBeMolStar(height=500, molecule_id='1qyn', sizing_mode='stretch_width')" - ] - }, - "execution_count": 5, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "1007" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "PDBeMolStar(\n", " height=500,\n", @@ -536,64 +66,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "PDBeMolStar(custom_data={'url': 'http://localhost:...}, height=500, name='Local File', sizing_mode='stretch_width')" - ] - }, - "execution_count": 6, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "1010" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "PDBeMolStar(\n", " name='Local File',\n", @@ -894,8 +369,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/examples/reference/Py3DMol.ipynb b/examples/reference/Py3DMol.ipynb index ccde4af..6f946eb 100644 --- a/examples/reference/Py3DMol.ipynb +++ b/examples/reference/Py3DMol.ipynb @@ -307,8 +307,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.4" + "pygments_lexer": "ipython3" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index b295611..e261f6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ "Topic :: Software Development :: Libraries", ] dependencies = [ - "panel", + "panel>=1.0", ] dynamic = ["version"] @@ -65,7 +65,7 @@ profile = "black" src_paths = ["src", "tests"] [tool.pylint.main] -py-version=3.9 +py-version=3.10 output-format = "colorized" max-attributes=12 max-args=10 @@ -75,7 +75,7 @@ max-module-lines = 1000 max-line-length=100 [tool.mypy] -python_version = "3.9" +python_version = "3.10" namespace_packages = true explicit_package_bases = true mypy_path = "src" diff --git a/src/panel_chemistry/__init__.py b/src/panel_chemistry/__init__.py index 5710cf0..b0828c8 100644 --- a/src/panel_chemistry/__init__.py +++ b/src/panel_chemistry/__init__.py @@ -2,4 +2,4 @@ develop high-quality [Panel](https://awesome-panel.org) **data apps** within the domain of **chemistry**. """ -VERSION = "0.2.2" +VERSION = "0.3.0" diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.py b/src/panel_chemistry/bokeh_extensions/jsme_editor.py index 15f87a4..cb428f1 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.py +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.py @@ -1,14 +1,14 @@ """A Bokeh model for the JSMEEditor""" from bokeh.core.properties import List, String -from bokeh.models import HTMLBox from panel import extension +from panel.models.layout import HTMLBox # pylint: disable=protected-access extension._imports["jsme"] = "panel_chemistry.bokeh_extensions.jsme_editor" # pylint: enable=protected-access -class JSMEEditor(HTMLBox): +class JSMEEditor(HTMLBox): # pylint: disable=too-few-public-methods,too-many-ancestors """JSMEEditor Bokeh Model""" __javascript__ = ["https://unpkg.com/jsme-editor@0.8.2/jsme.nocache.js"] diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts index 6f048c7..e1f5586 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts @@ -1,5 +1,5 @@ // See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html -import { HTMLBox, HTMLBoxView } from "@bokehjs/models/layouts/html_box" +import { HTMLBox, HTMLBoxView } from "./layout" // See https://docs.bokeh.org/en/latest/docs/reference/core/properties.html import * as p from "@bokehjs/core/properties" diff --git a/src/panel_chemistry/bokeh_extensions/layout.ts b/src/panel_chemistry/bokeh_extensions/layout.ts new file mode 100644 index 0000000..7a0d8ea --- /dev/null +++ b/src/panel_chemistry/bokeh_extensions/layout.ts @@ -0,0 +1,97 @@ +import {isArray} from "@bokehjs/core/util/types" +import {LayoutDOM, LayoutDOMView} from "@bokehjs/models/layouts/layout_dom" +import * as p from "@bokehjs/core/properties" + +export function set_size(el: HTMLElement, model: HTMLBox, adjustMargin: boolean = true): void { + let width_policy = model.width != null ? "fixed" : "fit" + let height_policy = model.height != null ? "fixed" : "fit" + const {sizing_mode, margin} = model + if (sizing_mode != null) { + if (sizing_mode == "fixed") + width_policy = height_policy = "fixed" + else if (sizing_mode == "stretch_both") + width_policy = height_policy = "max" + else if (sizing_mode == "stretch_width") + width_policy = "max" + else if (sizing_mode == "stretch_height") + height_policy = "max" + else { + switch (sizing_mode) { + case "scale_width": + width_policy = "max" + height_policy = "min" + break + case "scale_height": + width_policy = "min" + height_policy = "max" + break + case "scale_both": + width_policy = "max" + height_policy = "max" + break + default: + throw new Error("unreachable") + } + } + } + let wm: number, hm: number + if (!adjustMargin) { + hm = wm = 0 + } else if (isArray(margin)) { + if (margin.length === 4) { + hm = margin[0] + margin[2] + wm = margin[1] + margin[3] + } else { + hm = margin[0] * 2 + wm = margin[1] * 2 + } + } else if (margin == null) { + hm = wm = 0 + } else { + wm = hm = margin * 2 + } + if (width_policy == "fixed" && model.width) + el.style.width = model.width + "px"; + else if (width_policy == "max") + el.style.width = wm ? `calc(100% - ${wm}px)`: "100%"; + if (model.min_width != null) + el.style.minWidth = model.min_width + "px"; + if (model.max_width != null) + el.style.maxWidth = model.max_width + "px"; + if (height_policy == "fixed" && model.height) + el.style.height = model.height + "px"; + else if (height_policy == "max") + el.style.height = hm ? `calc(100% - ${hm}px)`: "100%"; + if (model.min_height != null) + el.style.minHeight = model.min_height + "px"; + if (model.max_width != null) + el.style.maxHeight = model.max_height + "px"; + } + + export abstract class HTMLBoxView extends LayoutDOMView { + override model: HTMLBox + + render(): void { + super.render() + set_size(this.el, this.model) + } + + get child_models(): LayoutDOM[] { + return [] + } + } + + export namespace HTMLBox { + export type Attrs = p.AttrsOf + export type Props = LayoutDOM.Props + } + + export interface HTMLBox extends HTMLBox.Attrs {} + + export abstract class HTMLBox extends LayoutDOM { + override properties: HTMLBox.Props + + constructor(attrs?: Partial) { + super(attrs) + } + } \ No newline at end of file diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py index a40a2bd..b15adce 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py @@ -3,11 +3,12 @@ from bokeh.models import LayoutDOM -class NGLViewer(LayoutDOM): +class NGLViewer(LayoutDOM): # pylint: disable=too-many-ancestors """The [NGL Viewer](https://github.com/nglviewer/ngl) can be used to show and analyse pdb molecule structures""" object = String() + background_color = String() extension = String() representation = String() color_scheme = String() diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts index e69f961..0790ddf 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts @@ -1,5 +1,5 @@ import * as p from "@bokehjs/core/properties" -import {HTMLBox, HTMLBoxView} from "@bokehjs/models/layouts/html_box" +import {HTMLBox, HTMLBoxView} from "./layout" declare namespace NGL { class AtomProxy{ @@ -96,7 +96,7 @@ export class NGLViewerView extends HTMLBoxView { this.connect(this.model.properties.color_scheme.change, this.updateParameters) this.connect(this.model.properties.custom_color_scheme.change, this.updateParameters) this.connect(this.model.properties.effect.change, this.updateEffect) - this.connect(this.model.properties.background.change, this.setBackgroundcolor) + this.connect(this.model.properties.background_color.change, this.setBackgroundcolor) } render(): void { @@ -115,8 +115,8 @@ export class NGLViewerView extends HTMLBoxView { }, false ); } setBackgroundcolor(): void { - console.log(this.model.background) - this._stage.setParameters( { backgroundColor: this.model.background} ); + console.log(this.model.background_color) + this._stage.setParameters( { backgroundColor: this.model.background_color} ); } after_layout(): void { super.after_layout() @@ -177,6 +177,7 @@ export namespace NGLViewer { export type Attrs = p.AttrsOf export type Props = HTMLBox.Props & { object: p.Property, + background_color: p.Property, extension: p.Property, representation: p.Property, color_scheme: p.Property, @@ -201,6 +202,7 @@ export class NGLViewer extends HTMLBox { this.define(({ String, Any }) => ({ object: [ String, ""], extension: [ String, ""], + background_color: [ String, ""], representation: [ String, "ribbon"], color_scheme: [ String, "chainid"], custom_color_scheme: [ Any, "chainid"], diff --git a/src/panel_chemistry/package-lock.json b/src/panel_chemistry/package-lock.json index bdf256f..1c78725 100644 --- a/src/panel_chemistry/package-lock.json +++ b/src/panel_chemistry/package-lock.json @@ -1,784 +1,32 @@ { "name": "panel_chemistry", - "version": "0.2.2", + "version": "0.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "panel_chemistry", - "version": "0.2.2", + "version": "0.3.0", "license": "Apache 2.0", "dependencies": { - "@bokeh/bokehjs": "^2.4.3" - } - }, - "node_modules/@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "dependencies": { - "regenerator-runtime": "^0.13.4" + "@bokeh/bokehjs": "~3.1.1" } }, "node_modules/@bokeh/bokehjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.4.3.tgz", - "integrity": "sha512-zORGCM+3A2if+owfH03QFCL4GdnkhZizMlGjjGekAOp7Hc4TRqH9rQolEKKaNov7pmIay/VAMjZX4pyMXYW+Ag==", - "dependencies": { - "@bokeh/numbro": "^1.6.2", - "@bokeh/slickgrid": "~2.4.2702", - "choices.js": "^9.0.1", - "es5-ext": "^0.10.53", - "es6-map": "^0.1.5", - "es6-promise": "4.2.8", - "es6-set": "^0.1.5", - "es6-symbol": "^3.1.3", - "es6-weak-map": "^2.0.2", - "flatbush": "^3.2.1", - "flatpickr": "4.6.6", - "hammerjs": "^2.0.4", - "mathjax-full": "^3.2.0", - "nouislider": "^15.4.0", - "proj4": "^2.7.5", - "regl": "^2.1.0", - "sprintf-js": "^1.1.2", - "timezone": "^1.0.23", - "tslib": "^2.3.1", - "underscore.template": "^0.1.7" - }, - "engines": { - "node": ">=14", - "npm": ">=7.4" - } - }, - "node_modules/@bokeh/numbro": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@bokeh/numbro/-/numbro-1.6.2.tgz", - "integrity": "sha512-owIECPc3T3QXHCb2v5Ez+/uE9SIxI7N4nd9iFlWnfBrOelr0/omvFn09VisRn37AAFAY39sJiCVgECwryHWUPA==", - "engines": { - "node": "*" - } - }, - "node_modules/@bokeh/slickgrid": { - "version": "2.4.2702", - "resolved": "https://registry.npmjs.org/@bokeh/slickgrid/-/slickgrid-2.4.2702.tgz", - "integrity": "sha512-W9tm8Qdw5BrylbZbaVWaQMgLfW/klesnj6J3FnyWpo18hCCOFApccUD8iOnRv7bF6PHlgWk84mW3JT5RSzYKjA==", - "dependencies": { - "@types/slickgrid": "^2.1.30", - "jquery": ">=3.4.0", - "jquery-ui": ">=1.8.0", - "tslib": "^1.10.0" - } - }, - "node_modules/@bokeh/slickgrid/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@types/jquery": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.5.tgz", - "integrity": "sha512-6RXU9Xzpc6vxNrS6FPPapN1SxSHgQ336WC6Jj/N8q30OiaBZ00l1GBgeP7usjVZPivSkGUfL1z/WW6TX989M+w==", - "dependencies": { - "@types/sizzle": "*" - } - }, - "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" - }, - "node_modules/@types/slickgrid": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/@types/slickgrid/-/slickgrid-2.1.30.tgz", - "integrity": "sha512-9nTqNWD3BtEVK0CP+G+mBtvSrKTfQy3Dg5/al+GdTSVMHFm37UxsHJ1eURwPg7rYu6vc7xU95fGTCKMZbxsD5w==", - "dependencies": { - "@types/jquery": "*" - } - }, - "node_modules/choices.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/choices.js/-/choices.js-9.0.1.tgz", - "integrity": "sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==", - "dependencies": { - "deepmerge": "^4.2.0", - "fuse.js": "^3.4.5", - "redux": "^4.0.4" - } - }, - "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "node_modules/es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } - }, - "node_modules/es6-set/node_modules/es6-symbol": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dependencies": { - "type": "^2.0.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" - }, - "node_modules/flatbush": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/flatbush/-/flatbush-3.3.0.tgz", - "integrity": "sha512-F3EzQvKpdmXUbFwWxLKBpytOFEGYQMCTBLuqZ4GEajFOEAvnOIBiyxW3OFSZXIOtpCS8teN6bFEpNZtnVXuDQA==", - "dependencies": { - "flatqueue": "^1.2.0" - } - }, - "node_modules/flatpickr": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.6.tgz", - "integrity": "sha512-EZ48CJMttMg3maMhJoX+GvTuuEhX/RbA1YeuI19attP3pwBdbYy6+yqAEVm0o0hSBFYBiLbVxscLW6gJXq6H3A==" - }, - "node_modules/flatqueue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/flatqueue/-/flatqueue-1.2.1.tgz", - "integrity": "sha512-X86TpWS1rGuY7m382HuA9vngLeDuWA9lJvhEG+GfgKMV5onSvx5a71cl7GMbXzhWtlN9dGfqOBrpfqeOtUfGYQ==" - }, - "node_modules/fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=", + "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.1.1.tgz", + "integrity": "sha512-+S3hqhIaOS17Xp0Oy7fB+hhOPe+v3jeIew40sWaH4/DEEMuUmhDZZMFowWhicuwTN9J6Bay9bp/62YJc5Na1Qg==", "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/jquery": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" - }, - "node_modules/jquery-ui": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.13.2.tgz", - "integrity": "sha512-wBZPnqWs5GaYJmo1Jj0k/mrSkzdQzKDwhXNtHKcBdAcKVxMM3KNYFq+iJ2i1rwiG53Z8M4mTn3Qxrm17uH1D4Q==", - "dependencies": { - "jquery": ">=1.8.0 <4.0.0" - } - }, - "node_modules/mathjax-full": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.0.tgz", - "integrity": "sha512-D2EBNvUG+mJyhn+M1C858k0f2Fc4KxXvbEX2WCMXroV10212JwfYqaBJ336ECBSz5X9L5LRoamxb7AJtg3KaJA==", - "dependencies": { - "esm": "^3.2.25", - "mhchemparser": "^4.1.0", - "mj-context-menu": "^0.6.1", - "speech-rule-engine": "^3.3.3" - } - }, - "node_modules/mgrs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", - "integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk=" - }, - "node_modules/mhchemparser": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz", - "integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==" - }, - "node_modules/mj-context-menu": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", - "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nouislider": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-15.5.0.tgz", - "integrity": "sha512-p0Rn0a4XzrBJ+JZRhNDYpRYr6sDPkajsjbvEQoTp/AZlNI3NirO15s1t11D25Gk3zVyvNJAzc1DO48cq/KX5Sw==" - }, - "node_modules/proj4": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.7.5.tgz", - "integrity": "sha512-5ecXUXbHAfvdhfBQpU7EhUfPCQGUCPmVup/4gnZA3bJY3JcK/xxzm4QQDz1xiXokN6ux65VDczlCtBtKrTSpAQ==", - "dependencies": { - "mgrs": "1.0.0", - "wkt-parser": "^1.3.1" - } - }, - "node_modules/redux": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", - "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "node_modules/regl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.0.tgz", - "integrity": "sha512-oWUce/aVoEvW5l2V0LK7O5KJMzUSKeiOwFuJehzpSFd43dO5spP9r+sSUfhKtsky4u6MCqWJaRL+abzExynfTg==" - }, - "node_modules/speech-rule-engine": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-3.3.3.tgz", - "integrity": "sha512-0exWw+0XauLjat+f/aFeo5T8SiDsO1JtwpY3qgJE4cWt+yL/Stl0WP4VNDWdh7lzGkubUD9lWP4J1ASnORXfyQ==", - "dependencies": { - "commander": ">=7.0.0", - "wicked-good-xpath": "^1.3.0", - "xmldom-sre": "^0.1.31" - }, - "bin": { - "sre": "bin/sre" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - }, - "node_modules/timezone": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/timezone/-/timezone-1.0.23.tgz", - "integrity": "sha512-yhQgk6qmSLB+TF8HGmApZAVI5bfzR1CoKUGr+WMZWmx75ED1uDewAZA8QMGCQ70TEv4GmM8pDB9jrHuxdaQ1PA==" - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/underscore.template": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/underscore.template/-/underscore.template-0.1.7.tgz", - "integrity": "sha1-MBPg6hgXVjBvFgnpWcr7xyKts+k=" - }, - "node_modules/wicked-good-xpath": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", - "integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=" - }, - "node_modules/wkt-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.1.tgz", - "integrity": "sha512-XK5qV+Y5gsygQfHx2/cS5a7Zxsgleaw8iX5UPC5eOXPc0TgJAu1JB9lr0iYYX3zAnN3p0aNiaN5c+1Bdblxwrg==" - }, - "node_modules/xmldom-sre": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", - "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==", - "engines": { - "node": ">=0.1" + "node": ">=16.0", + "npm": ">=8.0" } } }, "dependencies": { - "@babel/runtime": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", - "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, "@bokeh/bokehjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-2.4.3.tgz", - "integrity": "sha512-zORGCM+3A2if+owfH03QFCL4GdnkhZizMlGjjGekAOp7Hc4TRqH9rQolEKKaNov7pmIay/VAMjZX4pyMXYW+Ag==", - "requires": { - "@bokeh/numbro": "^1.6.2", - "@bokeh/slickgrid": "~2.4.2702", - "choices.js": "^9.0.1", - "es5-ext": "^0.10.53", - "es6-map": "^0.1.5", - "es6-promise": "4.2.8", - "es6-set": "^0.1.5", - "es6-symbol": "^3.1.3", - "es6-weak-map": "^2.0.2", - "flatbush": "^3.2.1", - "flatpickr": "4.6.6", - "hammerjs": "^2.0.4", - "mathjax-full": "^3.2.0", - "nouislider": "^15.4.0", - "proj4": "^2.7.5", - "regl": "^2.1.0", - "sprintf-js": "^1.1.2", - "timezone": "^1.0.23", - "tslib": "^2.3.1", - "underscore.template": "^0.1.7" - } - }, - "@bokeh/numbro": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@bokeh/numbro/-/numbro-1.6.2.tgz", - "integrity": "sha512-owIECPc3T3QXHCb2v5Ez+/uE9SIxI7N4nd9iFlWnfBrOelr0/omvFn09VisRn37AAFAY39sJiCVgECwryHWUPA==" - }, - "@bokeh/slickgrid": { - "version": "2.4.2702", - "resolved": "https://registry.npmjs.org/@bokeh/slickgrid/-/slickgrid-2.4.2702.tgz", - "integrity": "sha512-W9tm8Qdw5BrylbZbaVWaQMgLfW/klesnj6J3FnyWpo18hCCOFApccUD8iOnRv7bF6PHlgWk84mW3JT5RSzYKjA==", - "requires": { - "@types/slickgrid": "^2.1.30", - "jquery": ">=3.4.0", - "jquery-ui": ">=1.8.0", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - }, - "@types/jquery": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.5.tgz", - "integrity": "sha512-6RXU9Xzpc6vxNrS6FPPapN1SxSHgQ336WC6Jj/N8q30OiaBZ00l1GBgeP7usjVZPivSkGUfL1z/WW6TX989M+w==", - "requires": { - "@types/sizzle": "*" - } - }, - "@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" - }, - "@types/slickgrid": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/@types/slickgrid/-/slickgrid-2.1.30.tgz", - "integrity": "sha512-9nTqNWD3BtEVK0CP+G+mBtvSrKTfQy3Dg5/al+GdTSVMHFm37UxsHJ1eURwPg7rYu6vc7xU95fGTCKMZbxsD5w==", - "requires": { - "@types/jquery": "*" - } - }, - "choices.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/choices.js/-/choices.js-9.0.1.tgz", - "integrity": "sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==", - "requires": { - "deepmerge": "^4.2.0", - "fuse.js": "^3.4.5", - "redux": "^4.0.4" - } - }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - }, - "dependencies": { - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - } - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" - } - } - }, - "flatbush": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/flatbush/-/flatbush-3.3.0.tgz", - "integrity": "sha512-F3EzQvKpdmXUbFwWxLKBpytOFEGYQMCTBLuqZ4GEajFOEAvnOIBiyxW3OFSZXIOtpCS8teN6bFEpNZtnVXuDQA==", - "requires": { - "flatqueue": "^1.2.0" - } - }, - "flatpickr": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.6.tgz", - "integrity": "sha512-EZ48CJMttMg3maMhJoX+GvTuuEhX/RbA1YeuI19attP3pwBdbYy6+yqAEVm0o0hSBFYBiLbVxscLW6gJXq6H3A==" - }, - "flatqueue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/flatqueue/-/flatqueue-1.2.1.tgz", - "integrity": "sha512-X86TpWS1rGuY7m382HuA9vngLeDuWA9lJvhEG+GfgKMV5onSvx5a71cl7GMbXzhWtlN9dGfqOBrpfqeOtUfGYQ==" - }, - "fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==" - }, - "hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" - }, - "jquery": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", - "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" - }, - "jquery-ui": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.13.2.tgz", - "integrity": "sha512-wBZPnqWs5GaYJmo1Jj0k/mrSkzdQzKDwhXNtHKcBdAcKVxMM3KNYFq+iJ2i1rwiG53Z8M4mTn3Qxrm17uH1D4Q==", - "requires": { - "jquery": ">=1.8.0 <4.0.0" - } - }, - "mathjax-full": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.0.tgz", - "integrity": "sha512-D2EBNvUG+mJyhn+M1C858k0f2Fc4KxXvbEX2WCMXroV10212JwfYqaBJ336ECBSz5X9L5LRoamxb7AJtg3KaJA==", - "requires": { - "esm": "^3.2.25", - "mhchemparser": "^4.1.0", - "mj-context-menu": "^0.6.1", - "speech-rule-engine": "^3.3.3" - } - }, - "mgrs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", - "integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk=" - }, - "mhchemparser": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz", - "integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==" - }, - "mj-context-menu": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", - "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "nouislider": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-15.5.0.tgz", - "integrity": "sha512-p0Rn0a4XzrBJ+JZRhNDYpRYr6sDPkajsjbvEQoTp/AZlNI3NirO15s1t11D25Gk3zVyvNJAzc1DO48cq/KX5Sw==" - }, - "proj4": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.7.5.tgz", - "integrity": "sha512-5ecXUXbHAfvdhfBQpU7EhUfPCQGUCPmVup/4gnZA3bJY3JcK/xxzm4QQDz1xiXokN6ux65VDczlCtBtKrTSpAQ==", - "requires": { - "mgrs": "1.0.0", - "wkt-parser": "^1.3.1" - } - }, - "redux": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", - "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", - "requires": { - "@babel/runtime": "^7.9.2" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "regl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/regl/-/regl-2.1.0.tgz", - "integrity": "sha512-oWUce/aVoEvW5l2V0LK7O5KJMzUSKeiOwFuJehzpSFd43dO5spP9r+sSUfhKtsky4u6MCqWJaRL+abzExynfTg==" - }, - "speech-rule-engine": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-3.3.3.tgz", - "integrity": "sha512-0exWw+0XauLjat+f/aFeo5T8SiDsO1JtwpY3qgJE4cWt+yL/Stl0WP4VNDWdh7lzGkubUD9lWP4J1ASnORXfyQ==", - "requires": { - "commander": ">=7.0.0", - "wicked-good-xpath": "^1.3.0", - "xmldom-sre": "^0.1.31" - } - }, - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - }, - "timezone": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/timezone/-/timezone-1.0.23.tgz", - "integrity": "sha512-yhQgk6qmSLB+TF8HGmApZAVI5bfzR1CoKUGr+WMZWmx75ED1uDewAZA8QMGCQ70TEv4GmM8pDB9jrHuxdaQ1PA==" - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "underscore.template": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/underscore.template/-/underscore.template-0.1.7.tgz", - "integrity": "sha1-MBPg6hgXVjBvFgnpWcr7xyKts+k=" - }, - "wicked-good-xpath": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", - "integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=" - }, - "wkt-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.1.tgz", - "integrity": "sha512-XK5qV+Y5gsygQfHx2/cS5a7Zxsgleaw8iX5UPC5eOXPc0TgJAu1JB9lr0iYYX3zAnN3p0aNiaN5c+1Bdblxwrg==" - }, - "xmldom-sre": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", - "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.1.1.tgz", + "integrity": "sha512-+S3hqhIaOS17Xp0Oy7fB+hhOPe+v3jeIew40sWaH4/DEEMuUmhDZZMFowWhicuwTN9J6Bay9bp/62YJc5Na1Qg==" } } } diff --git a/src/panel_chemistry/package.json b/src/panel_chemistry/package.json index 7c42cae..58a1b1b 100644 --- a/src/panel_chemistry/package.json +++ b/src/panel_chemistry/package.json @@ -1,10 +1,10 @@ { "name": "panel_chemistry", - "version": "0.2.2", + "version": "0.3.0", "description": "Panel extension for data analysis and data apps within the domain of Chemistry", "license": "Apache 2.0", "keywords": [], "dependencies": { - "@bokeh/bokehjs": "^2.4.3" + "@bokeh/bokehjs": "~3.1.1" } } diff --git a/src/panel_chemistry/pane/ngl_viewer.py b/src/panel_chemistry/pane/ngl_viewer.py index 383e0ec..addbd42 100644 --- a/src/panel_chemistry/pane/ngl_viewer.py +++ b/src/panel_chemistry/pane/ngl_viewer.py @@ -8,8 +8,6 @@ """ -from typing import Dict - import param from panel import extension from panel.pane.base import PaneBase @@ -103,6 +101,10 @@ class NGLViewer(PaneBase): # pylint: disable=too-many-ancestors You can also specify a extension string if you define the extension in the extension parameter""" ) + background_color = param.Color( + doc=""" + A custom background color""" + ) extension = param.ObjectSelector( default="", objects=EXTENSIONS, diff --git a/src/panel_chemistry/pane/pdbe_molstar.py b/src/panel_chemistry/pane/pdbe_molstar.py index ce84a3d..c8d18c4 100644 --- a/src/panel_chemistry/pane/pdbe_molstar.py +++ b/src/panel_chemistry/pane/pdbe_molstar.py @@ -29,6 +29,7 @@ "spacefill", ] + # See https://embed.plnkr.co/plunk/m3GxFYx9cBjIanBp for an example JS implementation class PDBeMolStar(ReactiveHTML): # pylint: disable=too-many-ancestors """PDBe MolStar structure viewer. @@ -127,10 +128,10 @@ class PDBeMolStar(ReactiveHTML): # pylint: disable=too-many-ancestors ) hide_controls = param.Boolean(default=True, doc="Hide the control menu") - + sequence_panel = param.Boolean( - default=True, - doc="Show the sequence panel. Currently shown only when the controls are toggled" + default=True, + doc="Show the sequence panel. Currently shown only when the controls are toggled", ) expanded = param.Boolean(default=False, doc="""Display full-screen by default on load""") diff --git a/src/panel_chemistry/widgets/jsme_editor.py b/src/panel_chemistry/widgets/jsme_editor.py index fdece4f..d862b03 100644 --- a/src/panel_chemistry/widgets/jsme_editor.py +++ b/src/panel_chemistry/widgets/jsme_editor.py @@ -3,6 +3,10 @@ It is a wrapper of the free javascript JSME Molecule Editor. See https://jsme-editor.github.io/ """ +from __future__ import annotations + +from typing import ClassVar, Mapping + import param from panel.widgets.base import Widget @@ -67,11 +71,7 @@ class JSMEEditor(Widget): # pylint: disable=too-many-ancestors # Set the Bokeh model to use _widget_type = _BkJSMEEditor - # Rename Panel Parameters -> Bokeh Model properties - # Parameters like title that does not exist on the Bokeh model should be renamed to None - _rename = { - "title": None, - } + _rename: ClassVar[Mapping[str, str | None]] = {"name": None} # Parameters to be mapped to Bokeh model properties value = param.String( diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..d681a1c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,16 @@ +"""Shared fixtures""" +import pytest +from bokeh.document import Document +from pyviz_comms import Comm + + +@pytest.fixture +def document(): + """A Bokeh Document""" + return Document() + + +@pytest.fixture +def comm(): + """The pyviz communications""" + return Comm() diff --git a/tests/pane/test_ngl_viewer.py b/tests/pane/test_ngl_viewer.py index 2c17c63..f26db6c 100644 --- a/tests/pane/test_ngl_viewer.py +++ b/tests/pane/test_ngl_viewer.py @@ -5,21 +5,23 @@ from panel_chemistry.pane import NGLViewer -def test_can_create(): +def test_can_create(document, comm): """Test of the NGLViewer constructor""" - NGLViewer(object="1CRN", background="yellow", height=500) + viewer = NGLViewer(object="1CRN", background_color="yellow", height=500) + pane = viewer.get_root(document, comm=comm) + assert isinstance(pane, _BkNGLViewer) def test_has_bokeh_model(): """Test that the NGL Viewer Exists""" - assert _BkNGLViewer + assert _BkNGLViewer.__name__ -def test_app(): +def _create_app(): """Returns an app for manually testing the NGL Molecule Viewer""" pn.extension(sizing_mode="stretch_width") # 1NKT, 2GQ5, 3UOG and 5TXH - viewer = NGLViewer(object="1CRN", background="yellow", height=500) + viewer = NGLViewer(object="1CRN", background_color="yellow", height=500) parameters = [ "object", "extension", @@ -30,7 +32,7 @@ def test_app(): "sizing_mode", "width", "height", - "background", + "background_color", ] settings = pn.Param( viewer, @@ -46,5 +48,10 @@ def test_app(): ) +def test_app(): + """Can create test app""" + assert _create_app() + + if __name__.startswith("bokeh"): - test_app().servable() + _create_app().servable() diff --git a/tests/pane/test_pdbe_molstar_viewer.py b/tests/pane/test_pdbe_molstar_viewer.py index 6766e75..998f520 100644 --- a/tests/pane/test_pdbe_molstar_viewer.py +++ b/tests/pane/test_pdbe_molstar_viewer.py @@ -4,9 +4,11 @@ from panel_chemistry.pane import PDBeMolStar -def test_can_create(): +def test_can_create(document, comm): """Test of the PDBeMolStar constructor""" - PDBeMolStar(molecule_id="1qyn", lighting="metallic", height=300, width=300) + molstar = PDBeMolStar(molecule_id="1qyn", lighting="metallic", height=300, width=300) + widget = molstar.get_root(document, comm=comm) + assert widget def test_functions(): @@ -49,7 +51,7 @@ def test_functions(): viewer.reset(data) -def test_app(): +def _create_app(): """Returns an app for manually testing the PDBe Mol* Viewer""" pn.extension(sizing_mode="stretch_width") # 1NKT, 2GQ5, 3UOG and 5TXH @@ -102,5 +104,10 @@ def test_app(): return pn.Row(pn.WidgetBox(settings, width=300, sizing_mode="fixed"), viewer) +def test_app(): + """Can create test app""" + assert _create_app() + + if __name__.startswith("bokeh"): - test_app().servable() + _create_app().servable() diff --git a/tests/tests/test_jsme_editor.py b/tests/tests/test_jsme_editor.py index 13b5e1c..2b203a8 100644 --- a/tests/tests/test_jsme_editor.py +++ b/tests/tests/test_jsme_editor.py @@ -5,11 +5,13 @@ from panel_chemistry.widgets import JSMEEditor -def test_can_construct(): - JSMEEditor() +def test_can_construct(document, comm): + editor = JSMEEditor() + widget = editor.get_root(document, comm=comm) + assert isinstance(widget, editor._widget_type) # pylint: disable=protected-access -def test_jsme_editor_app(): +def _create_app(): pn.extension("jsme", sizing_mode="stretch_width") smiles = "N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O" editor = JSMEEditor(value=smiles, height=500) @@ -49,5 +51,9 @@ def test_jsme_editor_app(): ) +def test_app(): + assert _create_app() + + if __name__.startswith("bokeh"): - test_jsme_editor_app().servable() + _create_app().servable() From 1eeca025e78dc8560de65f7b7e0261e49169973f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Thu, 9 Nov 2023 12:09:29 +0100 Subject: [PATCH 02/11] Update JSMEEditor to work with Panel 1.0 / Bokeh 3.0 --- .../bokeh_extensions/jsme_editor.py | 30 ++++++++----- .../bokeh_extensions/jsme_editor.ts | 42 ++++++++++++++++--- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.py b/src/panel_chemistry/bokeh_extensions/jsme_editor.py index cb428f1..1c3a8e3 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.py +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.py @@ -11,17 +11,25 @@ class JSMEEditor(HTMLBox): # pylint: disable=too-few-public-methods,too-many-ancestors """JSMEEditor Bokeh Model""" - __javascript__ = ["https://unpkg.com/jsme-editor@0.8.2/jsme.nocache.js"] + __javascript__ = [ + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsme.nocache.js", + ] - value = String() - format = String() - subscriptions = List(String()) - options = List(String()) + __css__ = [ + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/mosaic.css", + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsa.css", + "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/chrome.css", + ] - jme = String() - smiles = String() - mol = String() - mol3000 = String() - sdf = String() + value = String(default="N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O") + format = String(default="smiles") + subscriptions = List(String, default=[]) + options = List(String, default=[]) - guicolor = String() + jme = String(default="") + smiles = String(default="") + mol = String(default="") + mol3000 = String(default="") + sdf = String(default="") + + guicolor = String(default="#c0c0c0") diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts index e1f5586..e03adb9 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts @@ -89,6 +89,14 @@ export class JSMEEditorView extends HTMLBoxView { JSME = (window as any).JSApplet.JSME valueFunc: any valueChanging: boolean = true + container: HTMLDivElement + + initialize(): void { + super.initialize() + this.container = div({ + style: {display: "contents"} + }) + } connect_signals(): void { super.connect_signals() @@ -125,8 +133,23 @@ export class JSMEEditorView extends HTMLBoxView { console.log("render - start") super.render() const id = "jsme-" + uuidv4() - const container = div({class: "jsme-editor", id: id}); - this.el.appendChild(container) + const el = div({ + class: "jsme-editor", + id: id, + style: {width: "100%", height: "100%"} + }) + this.container.appendChild(el) + + // wait for DOM to be updated + setTimeout(() => { this.createJSMEElement() }, 200); + } + + createJSMEElement() { + const id = this.container.children[0].id + + // Need to add it to document body for JSME to be able to find the id + document.body.appendChild(this.container) + this.jsmeElement = new this.JSME(id, this.getHeight(), this.getWidth(), { "options": this.model.options.join(","), "guicolor": this.model.guicolor @@ -144,6 +167,10 @@ export class JSMEEditorView extends HTMLBoxView { } this.jsmeElement.setAfterStructureModifiedCallback(showEvent); + // Remove from document body and add to shadow DOM + document.body.removeChild(this.container) + this.shadow_el.appendChild(this.container) + console.log("render - end") } @@ -180,7 +207,9 @@ export class JSMEEditorView extends HTMLBoxView { } resizeJSMEElement() { - this.jsmeElement.setSize(this.getWidth(), this.getHeight()); + if (this.jsmeElement !== undefined) { + this.jsmeElement.setSize(this.getWidth(), this.getHeight()); + } } after_layout(): void{ @@ -213,6 +242,7 @@ export interface JSMEEditor extends JSMEEditor.Attrs { } // The Bokeh .ts model corresponding to the Bokeh .py model export class JSMEEditor extends HTMLBox { properties: JSMEEditor.Props + __view_type__: JSMEEditorView constructor(attrs?: Partial) { super(attrs) @@ -220,11 +250,11 @@ export class JSMEEditor extends HTMLBox { static __module__ = "panel_chemistry.bokeh_extensions.jsme_editor" - static init_JSMEEditor(): void { + static { this.prototype.default_view = JSMEEditorView; this.define(({String, Array}) => ({ - value: [String, ""], + value: [String, "N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O"], format: [String, ""], options: [ Array(String), [] ], jme: [String, ""], @@ -236,4 +266,4 @@ export class JSMEEditor extends HTMLBox { guicolor: [String, "#c0c0c0"], })) } -} \ No newline at end of file +} From 7f8a79318800e827138191bd3e60296da8f76e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Thu, 9 Nov 2023 12:10:17 +0100 Subject: [PATCH 03/11] Update settings --- src/panel_chemistry/package-lock.json | 17 +++++------------ src/panel_chemistry/package.json | 2 +- src/panel_chemistry/tsconfig.json | 2 +- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/panel_chemistry/package-lock.json b/src/panel_chemistry/package-lock.json index 1c78725..892401f 100644 --- a/src/panel_chemistry/package-lock.json +++ b/src/panel_chemistry/package-lock.json @@ -1,7 +1,7 @@ { "name": "panel_chemistry", "version": "0.3.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,24 +9,17 @@ "version": "0.3.0", "license": "Apache 2.0", "dependencies": { - "@bokeh/bokehjs": "~3.1.1" + "@bokeh/bokehjs": "~3.3.0" } }, "node_modules/@bokeh/bokehjs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.1.1.tgz", - "integrity": "sha512-+S3hqhIaOS17Xp0Oy7fB+hhOPe+v3jeIew40sWaH4/DEEMuUmhDZZMFowWhicuwTN9J6Bay9bp/62YJc5Na1Qg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.3.0.tgz", + "integrity": "sha512-Y8wWO6VLkOPOMMrwMFPLcfTnTyi8vK+elMrxhxurU8E5IyABB9VypwTfSDCEnQsurGybm6f9OBH3YehUlRY/pQ==", "engines": { "node": ">=16.0", "npm": ">=8.0" } } - }, - "dependencies": { - "@bokeh/bokehjs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.1.1.tgz", - "integrity": "sha512-+S3hqhIaOS17Xp0Oy7fB+hhOPe+v3jeIew40sWaH4/DEEMuUmhDZZMFowWhicuwTN9J6Bay9bp/62YJc5Na1Qg==" - } } } diff --git a/src/panel_chemistry/package.json b/src/panel_chemistry/package.json index 58a1b1b..d659260 100644 --- a/src/panel_chemistry/package.json +++ b/src/panel_chemistry/package.json @@ -5,6 +5,6 @@ "license": "Apache 2.0", "keywords": [], "dependencies": { - "@bokeh/bokehjs": "~3.1.1" + "@bokeh/bokehjs": "~3.3.0" } } diff --git a/src/panel_chemistry/tsconfig.json b/src/panel_chemistry/tsconfig.json index 41720fb..6b4e52d 100644 --- a/src/panel_chemistry/tsconfig.json +++ b/src/panel_chemistry/tsconfig.json @@ -33,4 +33,4 @@ } }, "include": ["./**/*.ts"] -} \ No newline at end of file +} From b4d821fed7d39e4f5907071c85fb92aad7a63ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8xbro=20Hansen?= Date: Thu, 9 Nov 2023 12:21:57 +0100 Subject: [PATCH 04/11] Remove setTimeout --- .../bokeh_extensions/jsme_editor.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts index e03adb9..9f11ce8 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts @@ -90,6 +90,7 @@ export class JSMEEditorView extends HTMLBoxView { valueFunc: any valueChanging: boolean = true container: HTMLDivElement + _intialized: boolean = false initialize(): void { super.initialize() @@ -139,12 +140,13 @@ export class JSMEEditorView extends HTMLBoxView { style: {width: "100%", height: "100%"} }) this.container.appendChild(el) - - // wait for DOM to be updated - setTimeout(() => { this.createJSMEElement() }, 200); + this._intialized = false } createJSMEElement() { + if (this._intialized) + return + const id = this.container.children[0].id // Need to add it to document body for JSME to be able to find the id @@ -171,6 +173,7 @@ export class JSMEEditorView extends HTMLBoxView { document.body.removeChild(this.container) this.shadow_el.appendChild(this.container) + this._intialized = true console.log("render - end") } @@ -207,13 +210,12 @@ export class JSMEEditorView extends HTMLBoxView { } resizeJSMEElement() { - if (this.jsmeElement !== undefined) { - this.jsmeElement.setSize(this.getWidth(), this.getHeight()); - } + this.jsmeElement.setSize(this.getWidth(), this.getHeight()); } after_layout(): void{ super.after_layout() + this.createJSMEElement() this.resizeJSMEElement() } } From fb11380ebcce085c100d53f4bdfcd438f21bf55f Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Sun, 12 Nov 2023 19:38:32 +0000 Subject: [PATCH 05/11] finalize hoxbro contrib --- examples/reference/JSMEEditor.ipynb | 1354 ++++++++++++++++- package-lock.json | 10 + pyproject.toml | 3 +- .../bokeh_extensions/jsme_editor.py | 4 +- .../bokeh_extensions/jsme_editor.ts | 23 +- src/panel_chemistry/package-lock.json | 6 +- src/panel_chemistry/pane/py3dmol_viewer.py | 2 +- 7 files changed, 1361 insertions(+), 41 deletions(-) create mode 100644 package-lock.json diff --git a/examples/reference/JSMEEditor.ipynb b/examples/reference/JSMEEditor.ipynb index 37ba27c..65a7644 100644 --- a/examples/reference/JSMEEditor.ipynb +++ b/examples/reference/JSMEEditor.ipynb @@ -39,10 +39,1152 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "6b53c66f-a059-4727-8cc1-f502c7b800d7", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " var force = true;\n", + " var py_version = '3.3.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n", + " var reloading = false;\n", + " var Bokeh = root.Bokeh;\n", + " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", + "\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " }\n", + " if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + " if (!reloading) {\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error() {\n", + " console.error(\"failed to load \" + url);\n", + " }\n", + "\n", + " var skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n", + " require([\"jspanel\"], function(jsPanel) {\n", + "\twindow.jsPanel = jsPanel\n", + "\ton_load()\n", + " })\n", + " require([\"jspanel-modal\"], function() {\n", + "\ton_load()\n", + " })\n", + " require([\"jspanel-tooltip\"], function() {\n", + "\ton_load()\n", + " })\n", + " require([\"jspanel-hint\"], function() {\n", + "\ton_load()\n", + " })\n", + " require([\"jspanel-layout\"], function() {\n", + "\ton_load()\n", + " })\n", + " require([\"jspanel-contextmenu\"], function() {\n", + "\ton_load()\n", + " })\n", + " require([\"jspanel-dock\"], function() {\n", + "\ton_load()\n", + " })\n", + " require([\"gridstack\"], function(GridStack) {\n", + "\twindow.GridStack = GridStack\n", + "\ton_load()\n", + " })\n", + " require([\"notyf\"], function() {\n", + "\ton_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 9;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " var existing_stylesheets = []\n", + " var links = document.getElementsByTagName('link')\n", + " for (var i = 0; i < links.length; i++) {\n", + " var link = links[i]\n", + " if (link.href != null) {\n", + "\texisting_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (var i = 0; i < css_urls.length; i++) {\n", + " var url = css_urls[i];\n", + " if (existing_stylesheets.indexOf(url) !== -1) {\n", + "\ton_load()\n", + "\tcontinue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(urls[i])\n", + " }\n", + " } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(urls[i])\n", + " }\n", + " } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(urls[i])\n", + " }\n", + " } var existing_scripts = []\n", + " var scripts = document.getElementsByTagName('script')\n", + " for (var i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + "\texisting_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (var i = 0; i < js_urls.length; i++) {\n", + " var url = js_urls[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (var i = 0; i < js_modules.length; i++) {\n", + " var url = js_modules[i];\n", + " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " var url = js_exports[name];\n", + " if (skip.indexOf(url) >= 0 || root[name] != null) {\n", + "\tif (!window.requirejs) {\n", + "\t on_load();\n", + "\t}\n", + "\tcontinue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " var js_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsme.nocache.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.0.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n", + " var js_modules = [];\n", + " var js_exports = {};\n", + " var css_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/mosaic.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsa.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/chrome.css\"];\n", + " var inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + " function(Bokeh) {\n", + " /* BEGIN panel_chemistry.js */\n", + " /*!\n", + " * Copyright (c) 2012 - 2023, Anaconda, Inc., and Bokeh Contributors\n", + " * All rights reserved.\n", + " * \n", + " * Redistribution and use in source and binary forms, with or without modification,\n", + " * are permitted provided that the following conditions are met:\n", + " * \n", + " * Redistributions of source code must retain the above copyright notice,\n", + " * this list of conditions and the following disclaimer.\n", + " * \n", + " * Redistributions in binary form must reproduce the above copyright notice,\n", + " * this list of conditions and the following disclaimer in the documentation\n", + " * and/or other materials provided with the distribution.\n", + " * \n", + " * Neither the name of Anaconda nor the names of any contributors\n", + " * may be used to endorse or promote products derived from this software\n", + " * without specific prior written permission.\n", + " * \n", + " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n", + " * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n", + " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n", + " * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n", + " * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n", + " * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n", + " * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n", + " * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n", + " * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n", + " * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n", + " * THE POSSIBILITY OF SUCH DAMAGE.\n", + " */\n", + " (function(root, factory) {\n", + " factory(root[\"Bokeh\"], undefined);\n", + " })(this, function(Bokeh, version) {\n", + " let define;\n", + " return (function(modules, entry, aliases, externals) {\n", + " const bokeh = typeof Bokeh !== \"undefined\" && (version != null ? Bokeh[version] : Bokeh);\n", + " if (bokeh != null) {\n", + " return bokeh.register_plugin(modules, entry, aliases);\n", + " } else {\n", + " throw new Error(\"Cannot find Bokeh \" + version + \". You have to load it prior to loading plugins.\");\n", + " }\n", + " })\n", + " ({\n", + " \"82ab290c02\": /* index.js */ function _(require, module, exports, __esModule, __esExport) {\n", + " __esModule();\n", + " const tslib_1 = require(\"tslib\");\n", + " const PanelChemistryExtensions = tslib_1.__importStar(require(\"86de82b1ae\") /* ./bokeh_extensions/ */);\n", + " exports.PanelChemistryExtensions = PanelChemistryExtensions;\n", + " const base_1 = require(\"@bokehjs/base\");\n", + " (0, base_1.register_models)(PanelChemistryExtensions);\n", + " },\n", + " \"86de82b1ae\": /* bokeh_extensions/index.js */ function _(require, module, exports, __esModule, __esExport) {\n", + " __esModule();\n", + " var jsme_editor_1 = require(\"001cd512a8\") /* ./jsme_editor */;\n", + " __esExport(\"JSMEEditor\", jsme_editor_1.JSMEEditor);\n", + " var ngl_viewer_1 = require(\"516ed336e4\") /* ./ngl_viewer */;\n", + " __esExport(\"NGLViewer\", ngl_viewer_1.NGLViewer);\n", + " },\n", + " \"001cd512a8\": /* bokeh_extensions/jsme_editor.js */ function _(require, module, exports, __esModule, __esExport) {\n", + " __esModule();\n", + " var _a;\n", + " // See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html\n", + " const layout_1 = require(\"fc768a0766\") /* ./layout */;\n", + " const dom_1 = require(\"@bokehjs/core/dom\");\n", + " function uuidv4() {\n", + " return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n", + " var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n", + " return v.toString(16);\n", + " });\n", + " }\n", + " const notSubscribed = \"Not Subscribed\";\n", + " function readSDFValue(jsmeElement) {\n", + " var data = jsmeElement.getMultiSDFstack();\n", + " var output = \"No multirecords SDF was pasted into the editor \";\n", + " if (data.length > 0) {\n", + " output = data.join(\"$$$$\\n\") + \"$$$$\\n\";\n", + " }\n", + " return output;\n", + " }\n", + " function setModelValue(model, jsmeElement) {\n", + " var value = model.value;\n", + " if (model.format === \"smiles\") {\n", + " value = jsmeElement.smiles();\n", + " }\n", + " else if (model.format === \"mol\") {\n", + " value = jsmeElement.molFile(false);\n", + " }\n", + " else if (model.format === \"mol3000\") {\n", + " value = jsmeElement.molFile(true);\n", + " }\n", + " else if (model.format === \"sdf\") {\n", + " value = readSDFValue(jsmeElement);\n", + " }\n", + " else {\n", + " value = jsmeElement.jmeFile();\n", + " }\n", + " if (model.value !== value && value !== null) {\n", + " model.value = value;\n", + " }\n", + " }\n", + " function setModelValues(model, jsmeElement) {\n", + " setModelValue(model, jsmeElement);\n", + " setOtherModelValues(model, jsmeElement);\n", + " }\n", + " function resetOtherModelValues(model, jsmeElement) {\n", + " if (!model.subscriptions.includes(\"jme\")) {\n", + " model.jme = notSubscribed;\n", + " }\n", + " if (!model.subscriptions.includes(\"smiles\")) {\n", + " model.smiles = notSubscribed;\n", + " }\n", + " if (!model.subscriptions.includes(\"mol\")) {\n", + " model.mol = notSubscribed;\n", + " }\n", + " if (!model.subscriptions.includes(\"mol3000\")) {\n", + " model.mol3000 = notSubscribed;\n", + " }\n", + " if (!model.subscriptions.includes(\"sdf\")) {\n", + " model.sdf = notSubscribed;\n", + " }\n", + " setModelValues(model, jsmeElement);\n", + " }\n", + " function cleanValue(value) {\n", + " if (value === null) {\n", + " return \"null\";\n", + " }\n", + " else {\n", + " return value;\n", + " }\n", + " }\n", + " function setOtherModelValues(model, jsmeElement) {\n", + " if (model.subscriptions.includes(\"jme\")) {\n", + " model.jme = cleanValue(jsmeElement.jmeFile());\n", + " }\n", + " if (model.subscriptions.includes(\"smiles\")) {\n", + " model.smiles = cleanValue(jsmeElement.smiles());\n", + " }\n", + " if (model.subscriptions.includes(\"mol\")) {\n", + " model.mol = cleanValue(jsmeElement.molFile(false));\n", + " }\n", + " if (model.subscriptions.includes(\"mol3000\")) {\n", + " model.mol3000 = cleanValue(jsmeElement.molFile(true));\n", + " }\n", + " if (model.subscriptions.includes(\"sdf\")) {\n", + " model.sdf = cleanValue(readSDFValue(jsmeElement));\n", + " }\n", + " }\n", + " // The view of the Bokeh extension/ HTML element\n", + " // Here you can define how to render the model as well as react to model changes or View events.\n", + " class JSMEEditorView extends layout_1.HTMLBoxView {\n", + " constructor() {\n", + " super(...arguments);\n", + " this.JSME = window.JSApplet.JSME;\n", + " this.valueChanging = true;\n", + " this._intialized = false;\n", + " }\n", + " initialize() {\n", + " super.initialize();\n", + " this.container = (0, dom_1.div)({\n", + " style: { display: \"contents\" }\n", + " });\n", + " }\n", + " connect_signals() {\n", + " super.connect_signals();\n", + " this.connect(this.model.properties.value.change, () => {\n", + " if (!this.valueChanging) {\n", + " if (this.model.value === \"\") {\n", + " this.jsmeElement.reset();\n", + " }\n", + " else {\n", + " this.jsmeElement.readGenericMolecularInput(this.model.value);\n", + " }\n", + " }\n", + " });\n", + " this.connect(this.model.properties.format.change, () => {\n", + " setModelValue(this.model, this.jsmeElement);\n", + " });\n", + " this.connect(this.model.properties.subscriptions.change, () => {\n", + " resetOtherModelValues(this.model, this.jsmeElement);\n", + " });\n", + " this.connect(this.model.properties.options.change, () => {\n", + " this.setJSMEOptions();\n", + " });\n", + " this.connect(this.model.properties.guicolor.change, () => {\n", + " this.setGUIColor();\n", + " });\n", + " }\n", + " render() {\n", + " super.render();\n", + " const id = \"jsme-\" + uuidv4();\n", + " const el = (0, dom_1.div)({\n", + " class: \"jsme-editor\",\n", + " id: id,\n", + " style: { width: \"100%\", height: \"100%\" }\n", + " });\n", + " this.container.appendChild(el);\n", + " this._intialized = false;\n", + " }\n", + " createJSMEElement() {\n", + " if (this._intialized)\n", + " return;\n", + " const id = this.container.children[0].id;\n", + " // Need to add it to document body for JSME to be able to find the id\n", + " document.body.appendChild(this.container);\n", + " this.jsmeElement = new this.JSME(id, this.getHeight(), this.getWidth(), {\n", + " \"options\": this.model.options.join(\",\"),\n", + " \"guicolor\": this.model.guicolor\n", + " });\n", + " this.jsmeElement.readGenericMolecularInput(this.model.value);\n", + " resetOtherModelValues(this.model, this.jsmeElement);\n", + " setModelValues(this.model, this.jsmeElement);\n", + " const this_ = this;\n", + " function showEvent(_) {\n", + " this_.valueChanging = true;\n", + " setModelValues(this_.model, this_.jsmeElement);\n", + " this_.valueChanging = false;\n", + " }\n", + " this.jsmeElement.setAfterStructureModifiedCallback(showEvent);\n", + " // Remove from document body and add to shadow DOM\n", + " document.body.removeChild(this.container);\n", + " this.shadow_el.appendChild(this.container);\n", + " this._intialized = true;\n", + " }\n", + " setGUIColor() {\n", + " this.jsmeElement.setUserInterfaceBackgroundColor(this.model.guicolor);\n", + " }\n", + " setJSMEOptions() {\n", + " const options = this.model.options.join(\",\");\n", + " this.jsmeElement.options(options);\n", + " }\n", + " getHeight() {\n", + " if ((this.model.sizing_mode === \"stretch_height\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.height) {\n", + " return this.el.style.height;\n", + " }\n", + " else if (this.model.height) {\n", + " return this.model.height.toString() + \"px\";\n", + " }\n", + " else {\n", + " return \"100px\";\n", + " }\n", + " }\n", + " getWidth() {\n", + " if ((this.model.sizing_mode === \"stretch_width\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.width) {\n", + " return this.el.style.width;\n", + " }\n", + " else if (this.model.width) {\n", + " return this.model.width.toString() + \"px\";\n", + " }\n", + " else {\n", + " return \"100px\";\n", + " }\n", + " }\n", + " resizeJSMEElement() {\n", + " this.jsmeElement.setSize(this.getWidth(), this.getHeight());\n", + " }\n", + " after_layout() {\n", + " super.after_layout();\n", + " this.createJSMEElement();\n", + " this.resizeJSMEElement();\n", + " }\n", + " }\n", + " exports.JSMEEditorView = JSMEEditorView;\n", + " JSMEEditorView.__name__ = \"JSMEEditorView\";\n", + " // The Bokeh .ts model corresponding to the Bokeh .py model\n", + " class JSMEEditor extends layout_1.HTMLBox {\n", + " constructor(attrs) {\n", + " super(attrs);\n", + " }\n", + " }\n", + " exports.JSMEEditor = JSMEEditor;\n", + " _a = JSMEEditor;\n", + " JSMEEditor.__name__ = \"JSMEEditor\";\n", + " JSMEEditor.__module__ = \"panel_chemistry.bokeh_extensions.jsme_editor\";\n", + " (() => {\n", + " _a.prototype.default_view = JSMEEditorView;\n", + " _a.define(({ String, Array }) => ({\n", + " value: [String, \"N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O\"],\n", + " format: [String, \"\"],\n", + " options: [Array(String), []],\n", + " jme: [String, \"\"],\n", + " smiles: [String, \"\"],\n", + " mol: [String, \"\"],\n", + " mol3000: [String, \"\"],\n", + " sdf: [String, \"\"],\n", + " subscriptions: [Array(String), []],\n", + " guicolor: [String, \"#c0c0c0\"],\n", + " }));\n", + " })();\n", + " },\n", + " \"fc768a0766\": /* bokeh_extensions/layout.js */ function _(require, module, exports, __esModule, __esExport) {\n", + " __esModule();\n", + " const types_1 = require(\"@bokehjs/core/util/types\");\n", + " const layout_dom_1 = require(\"@bokehjs/models/layouts/layout_dom\");\n", + " function set_size(el, model, adjustMargin = true) {\n", + " let width_policy = model.width != null ? \"fixed\" : \"fit\";\n", + " let height_policy = model.height != null ? \"fixed\" : \"fit\";\n", + " const { sizing_mode, margin } = model;\n", + " if (sizing_mode != null) {\n", + " if (sizing_mode == \"fixed\")\n", + " width_policy = height_policy = \"fixed\";\n", + " else if (sizing_mode == \"stretch_both\")\n", + " width_policy = height_policy = \"max\";\n", + " else if (sizing_mode == \"stretch_width\")\n", + " width_policy = \"max\";\n", + " else if (sizing_mode == \"stretch_height\")\n", + " height_policy = \"max\";\n", + " else {\n", + " switch (sizing_mode) {\n", + " case \"scale_width\":\n", + " width_policy = \"max\";\n", + " height_policy = \"min\";\n", + " break;\n", + " case \"scale_height\":\n", + " width_policy = \"min\";\n", + " height_policy = \"max\";\n", + " break;\n", + " case \"scale_both\":\n", + " width_policy = \"max\";\n", + " height_policy = \"max\";\n", + " break;\n", + " default:\n", + " throw new Error(\"unreachable\");\n", + " }\n", + " }\n", + " }\n", + " let wm, hm;\n", + " if (!adjustMargin) {\n", + " hm = wm = 0;\n", + " }\n", + " else if ((0, types_1.isArray)(margin)) {\n", + " if (margin.length === 4) {\n", + " hm = margin[0] + margin[2];\n", + " wm = margin[1] + margin[3];\n", + " }\n", + " else {\n", + " hm = margin[0] * 2;\n", + " wm = margin[1] * 2;\n", + " }\n", + " }\n", + " else if (margin == null) {\n", + " hm = wm = 0;\n", + " }\n", + " else {\n", + " wm = hm = margin * 2;\n", + " }\n", + " if (width_policy == \"fixed\" && model.width)\n", + " el.style.width = model.width + \"px\";\n", + " else if (width_policy == \"max\")\n", + " el.style.width = wm ? `calc(100% - ${wm}px)` : \"100%\";\n", + " if (model.min_width != null)\n", + " el.style.minWidth = model.min_width + \"px\";\n", + " if (model.max_width != null)\n", + " el.style.maxWidth = model.max_width + \"px\";\n", + " if (height_policy == \"fixed\" && model.height)\n", + " el.style.height = model.height + \"px\";\n", + " else if (height_policy == \"max\")\n", + " el.style.height = hm ? `calc(100% - ${hm}px)` : \"100%\";\n", + " if (model.min_height != null)\n", + " el.style.minHeight = model.min_height + \"px\";\n", + " if (model.max_width != null)\n", + " el.style.maxHeight = model.max_height + \"px\";\n", + " }\n", + " exports.set_size = set_size;\n", + " class HTMLBoxView extends layout_dom_1.LayoutDOMView {\n", + " render() {\n", + " super.render();\n", + " set_size(this.el, this.model);\n", + " }\n", + " get child_models() {\n", + " return [];\n", + " }\n", + " }\n", + " exports.HTMLBoxView = HTMLBoxView;\n", + " HTMLBoxView.__name__ = \"HTMLBoxView\";\n", + " class HTMLBox extends layout_dom_1.LayoutDOM {\n", + " constructor(attrs) {\n", + " super(attrs);\n", + " }\n", + " }\n", + " exports.HTMLBox = HTMLBox;\n", + " HTMLBox.__name__ = \"HTMLBox\";\n", + " },\n", + " \"516ed336e4\": /* bokeh_extensions/ngl_viewer.js */ function _(require, module, exports, __esModule, __esExport) {\n", + " __esModule();\n", + " const layout_1 = require(\"fc768a0766\") /* ./layout */;\n", + " class NGLViewerView extends layout_1.HTMLBoxView {\n", + " connect_signals() {\n", + " super.connect_signals();\n", + " this.connect(this.model.properties.object.change, this.updateStage);\n", + " this.connect(this.model.properties.extension.change, this.updateStage);\n", + " this.connect(this.model.properties.representation.change, this.updateStage);\n", + " this.connect(this.model.properties.color_scheme.change, this.updateParameters);\n", + " this.connect(this.model.properties.custom_color_scheme.change, this.updateParameters);\n", + " this.connect(this.model.properties.effect.change, this.updateEffect);\n", + " this.connect(this.model.properties.background_color.change, this.setBackgroundcolor);\n", + " }\n", + " render() {\n", + " super.render();\n", + " this.el.id = \"viewport\";\n", + " const wn = window;\n", + " const ngl = wn.NGL;\n", + " this._stage = new ngl.Stage(this.el);\n", + " this.setBackgroundcolor();\n", + " const stage = this._stage;\n", + " this.updateStage();\n", + " window.addEventListener(\"resize\", function () {\n", + " stage.handleResize();\n", + " }, false);\n", + " }\n", + " setBackgroundcolor() {\n", + " console.log(this.model.background_color);\n", + " this._stage.setParameters({ backgroundColor: this.model.background_color });\n", + " }\n", + " after_layout() {\n", + " super.after_layout();\n", + " this._stage.handleResize();\n", + " }\n", + " updateEffect() {\n", + " if (this.model.effect === \"spin\") {\n", + " this._stage.setSpin(true);\n", + " }\n", + " else if (this.model.effect === \"rock\") {\n", + " this._stage.setRock(true);\n", + " }\n", + " else {\n", + " this._stage.setSpin(false);\n", + " this._stage.setRock(false);\n", + " }\n", + " }\n", + " getParameters() {\n", + " if (this.model.color_scheme === \"custom\") {\n", + " var list = this.model.custom_color_scheme;\n", + " var scheme = NGL.ColormakerRegistry.addSelectionScheme(list, \"new scheme\");\n", + " return { color: scheme };\n", + " }\n", + " else {\n", + " return { colorScheme: this.model.color_scheme };\n", + " }\n", + " }\n", + " updateParameters() {\n", + " const parameters = this.getParameters();\n", + " try {\n", + " this._stage.compList[0].reprList[0].setParameters(parameters);\n", + " }\n", + " catch (e) {\n", + " console.log(e);\n", + " }\n", + " }\n", + " updateStage() {\n", + " const model = this.model;\n", + " this._stage.removeAllComponents();\n", + " if (model.object === \"\") {\n", + " return;\n", + " }\n", + " const parameters = this.getParameters();\n", + " function finish(o) {\n", + " o.addRepresentation(model.representation, parameters);\n", + " o.autoView();\n", + " }\n", + " if (model.extension !== \"\") {\n", + " this._stage.loadFile(new Blob([model.object], { type: 'text/plain' }), { ext: model.extension }).then(finish);\n", + " }\n", + " else if (model.object.includes(\"://\")) {\n", + " this._stage.loadFile(model.object).then(finish);\n", + " }\n", + " else {\n", + " this._stage.loadFile(\"rcsb://\" + model.object).then(finish);\n", + " }\n", + " // this.updateColor()\n", + " this.updateEffect();\n", + " }\n", + " }\n", + " exports.NGLViewerView = NGLViewerView;\n", + " NGLViewerView.__name__ = \"NGLViewerView\";\n", + " class NGLViewer extends layout_1.HTMLBox {\n", + " constructor(attrs) {\n", + " super(attrs);\n", + " }\n", + " static init_NGLViewer() {\n", + " this.prototype.default_view = NGLViewerView;\n", + " this.define(({ String, Any }) => ({\n", + " object: [String, \"\"],\n", + " extension: [String, \"\"],\n", + " background_color: [String, \"\"],\n", + " representation: [String, \"ribbon\"],\n", + " color_scheme: [String, \"chainid\"],\n", + " custom_color_scheme: [Any, \"chainid\"],\n", + " effect: [String, \"\"],\n", + " }));\n", + " this.override({\n", + " height: 400,\n", + " width: 600\n", + " });\n", + " }\n", + " }\n", + " exports.NGLViewer = NGLViewer;\n", + " NGLViewer.__name__ = \"NGLViewer\";\n", + " NGLViewer.__module__ = \"panel_chemistry.bokeh_extensions.ngl_viewer\";\n", + " },\n", + " }, \"82ab290c02\", {\"index\":\"82ab290c02\",\"bokeh_extensions/index\":\"86de82b1ae\",\"bokeh_extensions/jsme_editor\":\"001cd512a8\",\"bokeh_extensions/layout\":\"fc768a0766\",\"bokeh_extensions/ngl_viewer\":\"516ed336e4\"}, {});});\n", + " //# sourceMappingURL=panel_chemistry.js.map\n", + "\n", + " /* END panel_chemistry.js */\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (var i = 0; i < inline_js.length; i++) {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + "\tvar NewBokeh = root.Bokeh;\n", + "\tif (Bokeh.versions === undefined) {\n", + "\t Bokeh.versions = new Map();\n", + "\t}\n", + "\tif (NewBokeh.version !== Bokeh.version) {\n", + "\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + "\t}\n", + "\troot.Bokeh = Bokeh;\n", + " }} else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " Bokeh = root.Bokeh;\n", + " bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " if (!reloading && (!bokeh_loaded || is_dev)) {\n", + "\troot.Bokeh = undefined;\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + "\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + "\trun_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsme.nocache.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.0.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/mosaic.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsa.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/chrome.css\"];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n function(Bokeh) {\n /* BEGIN panel_chemistry.js */\n /*!\n * Copyright (c) 2012 - 2023, Anaconda, Inc., and Bokeh Contributors\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n * \n * Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n * \n * Neither the name of Anaconda nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n */\n (function(root, factory) {\n factory(root[\"Bokeh\"], undefined);\n })(this, function(Bokeh, version) {\n let define;\n return (function(modules, entry, aliases, externals) {\n const bokeh = typeof Bokeh !== \"undefined\" && (version != null ? Bokeh[version] : Bokeh);\n if (bokeh != null) {\n return bokeh.register_plugin(modules, entry, aliases);\n } else {\n throw new Error(\"Cannot find Bokeh \" + version + \". You have to load it prior to loading plugins.\");\n }\n })\n ({\n \"82ab290c02\": /* index.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n const tslib_1 = require(\"tslib\");\n const PanelChemistryExtensions = tslib_1.__importStar(require(\"86de82b1ae\") /* ./bokeh_extensions/ */);\n exports.PanelChemistryExtensions = PanelChemistryExtensions;\n const base_1 = require(\"@bokehjs/base\");\n (0, base_1.register_models)(PanelChemistryExtensions);\n },\n \"86de82b1ae\": /* bokeh_extensions/index.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n var jsme_editor_1 = require(\"001cd512a8\") /* ./jsme_editor */;\n __esExport(\"JSMEEditor\", jsme_editor_1.JSMEEditor);\n var ngl_viewer_1 = require(\"516ed336e4\") /* ./ngl_viewer */;\n __esExport(\"NGLViewer\", ngl_viewer_1.NGLViewer);\n },\n \"001cd512a8\": /* bokeh_extensions/jsme_editor.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n var _a;\n // See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html\n const layout_1 = require(\"fc768a0766\") /* ./layout */;\n const dom_1 = require(\"@bokehjs/core/dom\");\n function uuidv4() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n }\n const notSubscribed = \"Not Subscribed\";\n function readSDFValue(jsmeElement) {\n var data = jsmeElement.getMultiSDFstack();\n var output = \"No multirecords SDF was pasted into the editor \";\n if (data.length > 0) {\n output = data.join(\"$$$$\\n\") + \"$$$$\\n\";\n }\n return output;\n }\n function setModelValue(model, jsmeElement) {\n var value = model.value;\n if (model.format === \"smiles\") {\n value = jsmeElement.smiles();\n }\n else if (model.format === \"mol\") {\n value = jsmeElement.molFile(false);\n }\n else if (model.format === \"mol3000\") {\n value = jsmeElement.molFile(true);\n }\n else if (model.format === \"sdf\") {\n value = readSDFValue(jsmeElement);\n }\n else {\n value = jsmeElement.jmeFile();\n }\n if (model.value !== value && value !== null) {\n model.value = value;\n }\n }\n function setModelValues(model, jsmeElement) {\n setModelValue(model, jsmeElement);\n setOtherModelValues(model, jsmeElement);\n }\n function resetOtherModelValues(model, jsmeElement) {\n if (!model.subscriptions.includes(\"jme\")) {\n model.jme = notSubscribed;\n }\n if (!model.subscriptions.includes(\"smiles\")) {\n model.smiles = notSubscribed;\n }\n if (!model.subscriptions.includes(\"mol\")) {\n model.mol = notSubscribed;\n }\n if (!model.subscriptions.includes(\"mol3000\")) {\n model.mol3000 = notSubscribed;\n }\n if (!model.subscriptions.includes(\"sdf\")) {\n model.sdf = notSubscribed;\n }\n setModelValues(model, jsmeElement);\n }\n function cleanValue(value) {\n if (value === null) {\n return \"null\";\n }\n else {\n return value;\n }\n }\n function setOtherModelValues(model, jsmeElement) {\n if (model.subscriptions.includes(\"jme\")) {\n model.jme = cleanValue(jsmeElement.jmeFile());\n }\n if (model.subscriptions.includes(\"smiles\")) {\n model.smiles = cleanValue(jsmeElement.smiles());\n }\n if (model.subscriptions.includes(\"mol\")) {\n model.mol = cleanValue(jsmeElement.molFile(false));\n }\n if (model.subscriptions.includes(\"mol3000\")) {\n model.mol3000 = cleanValue(jsmeElement.molFile(true));\n }\n if (model.subscriptions.includes(\"sdf\")) {\n model.sdf = cleanValue(readSDFValue(jsmeElement));\n }\n }\n // The view of the Bokeh extension/ HTML element\n // Here you can define how to render the model as well as react to model changes or View events.\n class JSMEEditorView extends layout_1.HTMLBoxView {\n constructor() {\n super(...arguments);\n this.JSME = window.JSApplet.JSME;\n this.valueChanging = true;\n this._intialized = false;\n }\n initialize() {\n super.initialize();\n this.container = (0, dom_1.div)({\n style: { display: \"contents\" }\n });\n }\n connect_signals() {\n super.connect_signals();\n this.connect(this.model.properties.value.change, () => {\n if (!this.valueChanging) {\n if (this.model.value === \"\") {\n this.jsmeElement.reset();\n }\n else {\n this.jsmeElement.readGenericMolecularInput(this.model.value);\n }\n }\n });\n this.connect(this.model.properties.format.change, () => {\n setModelValue(this.model, this.jsmeElement);\n });\n this.connect(this.model.properties.subscriptions.change, () => {\n resetOtherModelValues(this.model, this.jsmeElement);\n });\n this.connect(this.model.properties.options.change, () => {\n this.setJSMEOptions();\n });\n this.connect(this.model.properties.guicolor.change, () => {\n this.setGUIColor();\n });\n }\n render() {\n super.render();\n const id = \"jsme-\" + uuidv4();\n const el = (0, dom_1.div)({\n class: \"jsme-editor\",\n id: id,\n style: { width: \"100%\", height: \"100%\" }\n });\n this.container.appendChild(el);\n this._intialized = false;\n }\n createJSMEElement() {\n if (this._intialized)\n return;\n const id = this.container.children[0].id;\n // Need to add it to document body for JSME to be able to find the id\n document.body.appendChild(this.container);\n this.jsmeElement = new this.JSME(id, this.getHeight(), this.getWidth(), {\n \"options\": this.model.options.join(\",\"),\n \"guicolor\": this.model.guicolor\n });\n this.jsmeElement.readGenericMolecularInput(this.model.value);\n resetOtherModelValues(this.model, this.jsmeElement);\n setModelValues(this.model, this.jsmeElement);\n const this_ = this;\n function showEvent(_) {\n this_.valueChanging = true;\n setModelValues(this_.model, this_.jsmeElement);\n this_.valueChanging = false;\n }\n this.jsmeElement.setAfterStructureModifiedCallback(showEvent);\n // Remove from document body and add to shadow DOM\n document.body.removeChild(this.container);\n this.shadow_el.appendChild(this.container);\n this._intialized = true;\n }\n setGUIColor() {\n this.jsmeElement.setUserInterfaceBackgroundColor(this.model.guicolor);\n }\n setJSMEOptions() {\n const options = this.model.options.join(\",\");\n this.jsmeElement.options(options);\n }\n getHeight() {\n if ((this.model.sizing_mode === \"stretch_height\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.height) {\n return this.el.style.height;\n }\n else if (this.model.height) {\n return this.model.height.toString() + \"px\";\n }\n else {\n return \"100px\";\n }\n }\n getWidth() {\n if ((this.model.sizing_mode === \"stretch_width\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.width) {\n return this.el.style.width;\n }\n else if (this.model.width) {\n return this.model.width.toString() + \"px\";\n }\n else {\n return \"100px\";\n }\n }\n resizeJSMEElement() {\n this.jsmeElement.setSize(this.getWidth(), this.getHeight());\n }\n after_layout() {\n super.after_layout();\n this.createJSMEElement();\n this.resizeJSMEElement();\n }\n }\n exports.JSMEEditorView = JSMEEditorView;\n JSMEEditorView.__name__ = \"JSMEEditorView\";\n // The Bokeh .ts model corresponding to the Bokeh .py model\n class JSMEEditor extends layout_1.HTMLBox {\n constructor(attrs) {\n super(attrs);\n }\n }\n exports.JSMEEditor = JSMEEditor;\n _a = JSMEEditor;\n JSMEEditor.__name__ = \"JSMEEditor\";\n JSMEEditor.__module__ = \"panel_chemistry.bokeh_extensions.jsme_editor\";\n (() => {\n _a.prototype.default_view = JSMEEditorView;\n _a.define(({ String, Array }) => ({\n value: [String, \"N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O\"],\n format: [String, \"\"],\n options: [Array(String), []],\n jme: [String, \"\"],\n smiles: [String, \"\"],\n mol: [String, \"\"],\n mol3000: [String, \"\"],\n sdf: [String, \"\"],\n subscriptions: [Array(String), []],\n guicolor: [String, \"#c0c0c0\"],\n }));\n })();\n },\n \"fc768a0766\": /* bokeh_extensions/layout.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n const types_1 = require(\"@bokehjs/core/util/types\");\n const layout_dom_1 = require(\"@bokehjs/models/layouts/layout_dom\");\n function set_size(el, model, adjustMargin = true) {\n let width_policy = model.width != null ? \"fixed\" : \"fit\";\n let height_policy = model.height != null ? \"fixed\" : \"fit\";\n const { sizing_mode, margin } = model;\n if (sizing_mode != null) {\n if (sizing_mode == \"fixed\")\n width_policy = height_policy = \"fixed\";\n else if (sizing_mode == \"stretch_both\")\n width_policy = height_policy = \"max\";\n else if (sizing_mode == \"stretch_width\")\n width_policy = \"max\";\n else if (sizing_mode == \"stretch_height\")\n height_policy = \"max\";\n else {\n switch (sizing_mode) {\n case \"scale_width\":\n width_policy = \"max\";\n height_policy = \"min\";\n break;\n case \"scale_height\":\n width_policy = \"min\";\n height_policy = \"max\";\n break;\n case \"scale_both\":\n width_policy = \"max\";\n height_policy = \"max\";\n break;\n default:\n throw new Error(\"unreachable\");\n }\n }\n }\n let wm, hm;\n if (!adjustMargin) {\n hm = wm = 0;\n }\n else if ((0, types_1.isArray)(margin)) {\n if (margin.length === 4) {\n hm = margin[0] + margin[2];\n wm = margin[1] + margin[3];\n }\n else {\n hm = margin[0] * 2;\n wm = margin[1] * 2;\n }\n }\n else if (margin == null) {\n hm = wm = 0;\n }\n else {\n wm = hm = margin * 2;\n }\n if (width_policy == \"fixed\" && model.width)\n el.style.width = model.width + \"px\";\n else if (width_policy == \"max\")\n el.style.width = wm ? `calc(100% - ${wm}px)` : \"100%\";\n if (model.min_width != null)\n el.style.minWidth = model.min_width + \"px\";\n if (model.max_width != null)\n el.style.maxWidth = model.max_width + \"px\";\n if (height_policy == \"fixed\" && model.height)\n el.style.height = model.height + \"px\";\n else if (height_policy == \"max\")\n el.style.height = hm ? `calc(100% - ${hm}px)` : \"100%\";\n if (model.min_height != null)\n el.style.minHeight = model.min_height + \"px\";\n if (model.max_width != null)\n el.style.maxHeight = model.max_height + \"px\";\n }\n exports.set_size = set_size;\n class HTMLBoxView extends layout_dom_1.LayoutDOMView {\n render() {\n super.render();\n set_size(this.el, this.model);\n }\n get child_models() {\n return [];\n }\n }\n exports.HTMLBoxView = HTMLBoxView;\n HTMLBoxView.__name__ = \"HTMLBoxView\";\n class HTMLBox extends layout_dom_1.LayoutDOM {\n constructor(attrs) {\n super(attrs);\n }\n }\n exports.HTMLBox = HTMLBox;\n HTMLBox.__name__ = \"HTMLBox\";\n },\n \"516ed336e4\": /* bokeh_extensions/ngl_viewer.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n const layout_1 = require(\"fc768a0766\") /* ./layout */;\n class NGLViewerView extends layout_1.HTMLBoxView {\n connect_signals() {\n super.connect_signals();\n this.connect(this.model.properties.object.change, this.updateStage);\n this.connect(this.model.properties.extension.change, this.updateStage);\n this.connect(this.model.properties.representation.change, this.updateStage);\n this.connect(this.model.properties.color_scheme.change, this.updateParameters);\n this.connect(this.model.properties.custom_color_scheme.change, this.updateParameters);\n this.connect(this.model.properties.effect.change, this.updateEffect);\n this.connect(this.model.properties.background_color.change, this.setBackgroundcolor);\n }\n render() {\n super.render();\n this.el.id = \"viewport\";\n const wn = window;\n const ngl = wn.NGL;\n this._stage = new ngl.Stage(this.el);\n this.setBackgroundcolor();\n const stage = this._stage;\n this.updateStage();\n window.addEventListener(\"resize\", function () {\n stage.handleResize();\n }, false);\n }\n setBackgroundcolor() {\n console.log(this.model.background_color);\n this._stage.setParameters({ backgroundColor: this.model.background_color });\n }\n after_layout() {\n super.after_layout();\n this._stage.handleResize();\n }\n updateEffect() {\n if (this.model.effect === \"spin\") {\n this._stage.setSpin(true);\n }\n else if (this.model.effect === \"rock\") {\n this._stage.setRock(true);\n }\n else {\n this._stage.setSpin(false);\n this._stage.setRock(false);\n }\n }\n getParameters() {\n if (this.model.color_scheme === \"custom\") {\n var list = this.model.custom_color_scheme;\n var scheme = NGL.ColormakerRegistry.addSelectionScheme(list, \"new scheme\");\n return { color: scheme };\n }\n else {\n return { colorScheme: this.model.color_scheme };\n }\n }\n updateParameters() {\n const parameters = this.getParameters();\n try {\n this._stage.compList[0].reprList[0].setParameters(parameters);\n }\n catch (e) {\n console.log(e);\n }\n }\n updateStage() {\n const model = this.model;\n this._stage.removeAllComponents();\n if (model.object === \"\") {\n return;\n }\n const parameters = this.getParameters();\n function finish(o) {\n o.addRepresentation(model.representation, parameters);\n o.autoView();\n }\n if (model.extension !== \"\") {\n this._stage.loadFile(new Blob([model.object], { type: 'text/plain' }), { ext: model.extension }).then(finish);\n }\n else if (model.object.includes(\"://\")) {\n this._stage.loadFile(model.object).then(finish);\n }\n else {\n this._stage.loadFile(\"rcsb://\" + model.object).then(finish);\n }\n // this.updateColor()\n this.updateEffect();\n }\n }\n exports.NGLViewerView = NGLViewerView;\n NGLViewerView.__name__ = \"NGLViewerView\";\n class NGLViewer extends layout_1.HTMLBox {\n constructor(attrs) {\n super(attrs);\n }\n static init_NGLViewer() {\n this.prototype.default_view = NGLViewerView;\n this.define(({ String, Any }) => ({\n object: [String, \"\"],\n extension: [String, \"\"],\n background_color: [String, \"\"],\n representation: [String, \"ribbon\"],\n color_scheme: [String, \"chainid\"],\n custom_color_scheme: [Any, \"chainid\"],\n effect: [String, \"\"],\n }));\n this.override({\n height: 400,\n width: 600\n });\n }\n }\n exports.NGLViewer = NGLViewer;\n NGLViewer.__name__ = \"NGLViewer\";\n NGLViewer.__module__ = \"panel_chemistry.bokeh_extensions.ngl_viewer\";\n },\n }, \"82ab290c02\", {\"index\":\"82ab290c02\",\"bokeh_extensions/index\":\"86de82b1ae\",\"bokeh_extensions/jsme_editor\":\"001cd512a8\",\"bokeh_extensions/layout\":\"fc768a0766\",\"bokeh_extensions/ngl_viewer\":\"516ed336e4\"}, {});});\n //# sourceMappingURL=panel_chemistry.js.map\n\n /* END panel_chemistry.js */\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " console.log(message)\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " comm.open();\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " }) \n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "966119d9-2695-4cff-a96b-1b5cef13354e" + } + }, + "output_type": "display_data" + } + ], "source": [ "import panel as pn \n", "from panel_chemistry.widgets import JSMEEditor # panel_chemistry needs to be imported before you run pn.extension()\n", @@ -52,10 +1194,101 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "13bd929d-d3a5-4e2c-8c0b-492dc3e3d3d9", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "Column(sizing_mode='stretch_width')\n", + " [0] JSMEEditor(format='smiles', height=500, sizing_mode='stretch_width', value='N[C@@H](CCC(=O)N[C@@H](CS...)\n", + " [1] TextInput(description='A value definining t..., name='Value', sizing_mode='stretch_width', value='N[C@@H](CCC(=O)N[C@@H](CS...)" + ] + }, + "execution_count": 2, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "42a8815b-483b-4ba6-9b66-1a5a030f34eb" + } + }, + "output_type": "execute_result" + } + ], "source": [ "smiles=\"N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O\"\n", "editor = JSMEEditor(value=smiles, height=500, format=\"smiles\")\n", @@ -73,7 +1306,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "97c39491-6796-42c6-a28a-05480dddb7de", "metadata": {}, "outputs": [], @@ -90,7 +1323,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "fda4ce67-2e08-4dd1-8370-cc8b140880da", "metadata": {}, "outputs": [], @@ -104,10 +1337,104 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "f344ccb9-73ae-4797-b1a3-a40853270bce", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "Row(sizing_mode='stretch_width')\n", + " [0] Column(sizing_mode='stretch_width')\n", + " [0] JSMEEditor(format='smiles', height=500, sizing_mode='stretch_width', value='20 19 N 2.42 0...)\n", + " [1] Param(JSMEEditor, parameters=['value', 'jme', ...], sizing_mode='stretch_width', widgets={'value': {'type': { - console.log("value change", this.model.value) if (!this.valueChanging){ if (this.model.value===""){ this.jsmeElement.reset() @@ -113,25 +103,20 @@ export class JSMEEditorView extends HTMLBoxView { } }) this.connect(this.model.properties.format.change, () => { - console.log("format change", this.model.format) setModelValue(this.model, this.jsmeElement); }) this.connect(this.model.properties.subscriptions.change, () => { - console.log("subscriptions change", this.model.subscriptions) resetOtherModelValues(this.model, this.jsmeElement); }) this.connect(this.model.properties.options.change, () => { - console.log("options change", this.model.options) this.setJSMEOptions() }) this.connect(this.model.properties.guicolor.change, () => { - console.log("options change", this.model.options) this.setGUIColor() }) } render(): void { - console.log("render - start") super.render() const id = "jsme-" + uuidv4() const el = div({ @@ -161,8 +146,7 @@ export class JSMEEditorView extends HTMLBoxView { setModelValues(this.model, this.jsmeElement) const this_ = this; - function showEvent(event: any){ - console.log("event", event) + function showEvent(_: any){ this_.valueChanging = true setModelValues(this_.model, this_.jsmeElement) this_.valueChanging = false @@ -174,17 +158,14 @@ export class JSMEEditorView extends HTMLBoxView { this.shadow_el.appendChild(this.container) this._intialized = true - console.log("render - end") } setGUIColor(){ - console.log("setGUIColor", this.model.guicolor) this.jsmeElement.setUserInterfaceBackgroundColor(this.model.guicolor) } setJSMEOptions(){ const options = this.model.options.join(",") - console.log("setJSMEOptions", options) this.jsmeElement.options(options) } diff --git a/src/panel_chemistry/package-lock.json b/src/panel_chemistry/package-lock.json index 892401f..279c583 100644 --- a/src/panel_chemistry/package-lock.json +++ b/src/panel_chemistry/package-lock.json @@ -13,9 +13,9 @@ } }, "node_modules/@bokeh/bokehjs": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.3.0.tgz", - "integrity": "sha512-Y8wWO6VLkOPOMMrwMFPLcfTnTyi8vK+elMrxhxurU8E5IyABB9VypwTfSDCEnQsurGybm6f9OBH3YehUlRY/pQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@bokeh/bokehjs/-/bokehjs-3.3.1.tgz", + "integrity": "sha512-orQM4d6MP1g7sXpG6B76HcwQLZIwVAMfopU6n7pZEB5430mINNH5VXlAWloBDveavcEpOwy+c0vBZLTYqOsgBg==", "engines": { "node": ">=16.0", "npm": ">=8.0" diff --git a/src/panel_chemistry/pane/py3dmol_viewer.py b/src/panel_chemistry/pane/py3dmol_viewer.py index 9ad7657..d01d3b7 100644 --- a/src/panel_chemistry/pane/py3dmol_viewer.py +++ b/src/panel_chemistry/pane/py3dmol_viewer.py @@ -12,7 +12,7 @@ try: import py3Dmol except ModuleNotFoundError: - # pylint: disable=invalid-name + # pylint: disable=invalid-name, too-few-public-methods class py3Dmol(param.Parameterized): # type: ignore """Dummy py3Dmol class""" From 38a35a104036f314d519d53d8d145cc07b91cdf8 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Sun, 12 Nov 2023 19:39:45 +0000 Subject: [PATCH 06/11] clear outputs --- examples/reference/JSMEEditor.ipynb | 1347 +-------------------------- 1 file changed, 10 insertions(+), 1337 deletions(-) diff --git a/examples/reference/JSMEEditor.ipynb b/examples/reference/JSMEEditor.ipynb index 65a7644..c02b6a5 100644 --- a/examples/reference/JSMEEditor.ipynb +++ b/examples/reference/JSMEEditor.ipynb @@ -39,1152 +39,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "6b53c66f-a059-4727-8cc1-f502c7b800d7", "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "(function(root) {\n", - " function now() {\n", - " return new Date();\n", - " }\n", - "\n", - " var force = true;\n", - " var py_version = '3.3.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", - " var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n", - " var reloading = false;\n", - " var Bokeh = root.Bokeh;\n", - " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", - "\n", - " if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n", - " root._bokeh_timeout = Date.now() + 5000;\n", - " root._bokeh_failed_load = false;\n", - " }\n", - "\n", - " function run_callbacks() {\n", - " try {\n", - " root._bokeh_onload_callbacks.forEach(function(callback) {\n", - " if (callback != null)\n", - " callback();\n", - " });\n", - " } finally {\n", - " delete root._bokeh_onload_callbacks;\n", - " }\n", - " console.debug(\"Bokeh: all callbacks have finished\");\n", - " }\n", - "\n", - " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", - " if (css_urls == null) css_urls = [];\n", - " if (js_urls == null) js_urls = [];\n", - " if (js_modules == null) js_modules = [];\n", - " if (js_exports == null) js_exports = {};\n", - "\n", - " root._bokeh_onload_callbacks.push(callback);\n", - "\n", - " if (root._bokeh_is_loading > 0) {\n", - " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", - " return null;\n", - " }\n", - " if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", - " run_callbacks();\n", - " return null;\n", - " }\n", - " if (!reloading) {\n", - " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", - " }\n", - "\n", - " function on_load() {\n", - " root._bokeh_is_loading--;\n", - " if (root._bokeh_is_loading === 0) {\n", - " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", - " run_callbacks()\n", - " }\n", - " }\n", - " window._bokeh_on_load = on_load\n", - "\n", - " function on_error() {\n", - " console.error(\"failed to load \" + url);\n", - " }\n", - "\n", - " var skip = [];\n", - " if (window.requirejs) {\n", - " window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n", - " require([\"jspanel\"], function(jsPanel) {\n", - "\twindow.jsPanel = jsPanel\n", - "\ton_load()\n", - " })\n", - " require([\"jspanel-modal\"], function() {\n", - "\ton_load()\n", - " })\n", - " require([\"jspanel-tooltip\"], function() {\n", - "\ton_load()\n", - " })\n", - " require([\"jspanel-hint\"], function() {\n", - "\ton_load()\n", - " })\n", - " require([\"jspanel-layout\"], function() {\n", - "\ton_load()\n", - " })\n", - " require([\"jspanel-contextmenu\"], function() {\n", - "\ton_load()\n", - " })\n", - " require([\"jspanel-dock\"], function() {\n", - "\ton_load()\n", - " })\n", - " require([\"gridstack\"], function(GridStack) {\n", - "\twindow.GridStack = GridStack\n", - "\ton_load()\n", - " })\n", - " require([\"notyf\"], function() {\n", - "\ton_load()\n", - " })\n", - " root._bokeh_is_loading = css_urls.length + 9;\n", - " } else {\n", - " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", - " }\n", - "\n", - " var existing_stylesheets = []\n", - " var links = document.getElementsByTagName('link')\n", - " for (var i = 0; i < links.length; i++) {\n", - " var link = links[i]\n", - " if (link.href != null) {\n", - "\texisting_stylesheets.push(link.href)\n", - " }\n", - " }\n", - " for (var i = 0; i < css_urls.length; i++) {\n", - " var url = css_urls[i];\n", - " if (existing_stylesheets.indexOf(url) !== -1) {\n", - "\ton_load()\n", - "\tcontinue;\n", - " }\n", - " const element = document.createElement(\"link\");\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.rel = \"stylesheet\";\n", - " element.type = \"text/css\";\n", - " element.href = url;\n", - " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", - " document.body.appendChild(element);\n", - " } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n", - " var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n", - " for (var i = 0; i < urls.length; i++) {\n", - " skip.push(urls[i])\n", - " }\n", - " } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n", - " var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n", - " for (var i = 0; i < urls.length; i++) {\n", - " skip.push(urls[i])\n", - " }\n", - " } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n", - " var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n", - " for (var i = 0; i < urls.length; i++) {\n", - " skip.push(urls[i])\n", - " }\n", - " } var existing_scripts = []\n", - " var scripts = document.getElementsByTagName('script')\n", - " for (var i = 0; i < scripts.length; i++) {\n", - " var script = scripts[i]\n", - " if (script.src != null) {\n", - "\texisting_scripts.push(script.src)\n", - " }\n", - " }\n", - " for (var i = 0; i < js_urls.length; i++) {\n", - " var url = js_urls[i];\n", - " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", - "\tif (!window.requirejs) {\n", - "\t on_load();\n", - "\t}\n", - "\tcontinue;\n", - " }\n", - " var element = document.createElement('script');\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.src = url;\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " document.head.appendChild(element);\n", - " }\n", - " for (var i = 0; i < js_modules.length; i++) {\n", - " var url = js_modules[i];\n", - " if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n", - "\tif (!window.requirejs) {\n", - "\t on_load();\n", - "\t}\n", - "\tcontinue;\n", - " }\n", - " var element = document.createElement('script');\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.src = url;\n", - " element.type = \"module\";\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " document.head.appendChild(element);\n", - " }\n", - " for (const name in js_exports) {\n", - " var url = js_exports[name];\n", - " if (skip.indexOf(url) >= 0 || root[name] != null) {\n", - "\tif (!window.requirejs) {\n", - "\t on_load();\n", - "\t}\n", - "\tcontinue;\n", - " }\n", - " var element = document.createElement('script');\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.type = \"module\";\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " element.textContent = `\n", - " import ${name} from \"${url}\"\n", - " window.${name} = ${name}\n", - " window._bokeh_on_load()\n", - " `\n", - " document.head.appendChild(element);\n", - " }\n", - " if (!js_urls.length && !js_modules.length) {\n", - " on_load()\n", - " }\n", - " };\n", - "\n", - " function inject_raw_css(css) {\n", - " const element = document.createElement(\"style\");\n", - " element.appendChild(document.createTextNode(css));\n", - " document.body.appendChild(element);\n", - " }\n", - "\n", - " var js_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsme.nocache.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.0.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n", - " var js_modules = [];\n", - " var js_exports = {};\n", - " var css_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/mosaic.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsa.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/chrome.css\"];\n", - " var inline_js = [ function(Bokeh) {\n", - " Bokeh.set_log_level(\"info\");\n", - " },\n", - " function(Bokeh) {\n", - " /* BEGIN panel_chemistry.js */\n", - " /*!\n", - " * Copyright (c) 2012 - 2023, Anaconda, Inc., and Bokeh Contributors\n", - " * All rights reserved.\n", - " * \n", - " * Redistribution and use in source and binary forms, with or without modification,\n", - " * are permitted provided that the following conditions are met:\n", - " * \n", - " * Redistributions of source code must retain the above copyright notice,\n", - " * this list of conditions and the following disclaimer.\n", - " * \n", - " * Redistributions in binary form must reproduce the above copyright notice,\n", - " * this list of conditions and the following disclaimer in the documentation\n", - " * and/or other materials provided with the distribution.\n", - " * \n", - " * Neither the name of Anaconda nor the names of any contributors\n", - " * may be used to endorse or promote products derived from this software\n", - " * without specific prior written permission.\n", - " * \n", - " * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n", - " * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n", - " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n", - " * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n", - " * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n", - " * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n", - " * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n", - " * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n", - " * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n", - " * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n", - " * THE POSSIBILITY OF SUCH DAMAGE.\n", - " */\n", - " (function(root, factory) {\n", - " factory(root[\"Bokeh\"], undefined);\n", - " })(this, function(Bokeh, version) {\n", - " let define;\n", - " return (function(modules, entry, aliases, externals) {\n", - " const bokeh = typeof Bokeh !== \"undefined\" && (version != null ? Bokeh[version] : Bokeh);\n", - " if (bokeh != null) {\n", - " return bokeh.register_plugin(modules, entry, aliases);\n", - " } else {\n", - " throw new Error(\"Cannot find Bokeh \" + version + \". You have to load it prior to loading plugins.\");\n", - " }\n", - " })\n", - " ({\n", - " \"82ab290c02\": /* index.js */ function _(require, module, exports, __esModule, __esExport) {\n", - " __esModule();\n", - " const tslib_1 = require(\"tslib\");\n", - " const PanelChemistryExtensions = tslib_1.__importStar(require(\"86de82b1ae\") /* ./bokeh_extensions/ */);\n", - " exports.PanelChemistryExtensions = PanelChemistryExtensions;\n", - " const base_1 = require(\"@bokehjs/base\");\n", - " (0, base_1.register_models)(PanelChemistryExtensions);\n", - " },\n", - " \"86de82b1ae\": /* bokeh_extensions/index.js */ function _(require, module, exports, __esModule, __esExport) {\n", - " __esModule();\n", - " var jsme_editor_1 = require(\"001cd512a8\") /* ./jsme_editor */;\n", - " __esExport(\"JSMEEditor\", jsme_editor_1.JSMEEditor);\n", - " var ngl_viewer_1 = require(\"516ed336e4\") /* ./ngl_viewer */;\n", - " __esExport(\"NGLViewer\", ngl_viewer_1.NGLViewer);\n", - " },\n", - " \"001cd512a8\": /* bokeh_extensions/jsme_editor.js */ function _(require, module, exports, __esModule, __esExport) {\n", - " __esModule();\n", - " var _a;\n", - " // See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html\n", - " const layout_1 = require(\"fc768a0766\") /* ./layout */;\n", - " const dom_1 = require(\"@bokehjs/core/dom\");\n", - " function uuidv4() {\n", - " return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n", - " var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n", - " return v.toString(16);\n", - " });\n", - " }\n", - " const notSubscribed = \"Not Subscribed\";\n", - " function readSDFValue(jsmeElement) {\n", - " var data = jsmeElement.getMultiSDFstack();\n", - " var output = \"No multirecords SDF was pasted into the editor \";\n", - " if (data.length > 0) {\n", - " output = data.join(\"$$$$\\n\") + \"$$$$\\n\";\n", - " }\n", - " return output;\n", - " }\n", - " function setModelValue(model, jsmeElement) {\n", - " var value = model.value;\n", - " if (model.format === \"smiles\") {\n", - " value = jsmeElement.smiles();\n", - " }\n", - " else if (model.format === \"mol\") {\n", - " value = jsmeElement.molFile(false);\n", - " }\n", - " else if (model.format === \"mol3000\") {\n", - " value = jsmeElement.molFile(true);\n", - " }\n", - " else if (model.format === \"sdf\") {\n", - " value = readSDFValue(jsmeElement);\n", - " }\n", - " else {\n", - " value = jsmeElement.jmeFile();\n", - " }\n", - " if (model.value !== value && value !== null) {\n", - " model.value = value;\n", - " }\n", - " }\n", - " function setModelValues(model, jsmeElement) {\n", - " setModelValue(model, jsmeElement);\n", - " setOtherModelValues(model, jsmeElement);\n", - " }\n", - " function resetOtherModelValues(model, jsmeElement) {\n", - " if (!model.subscriptions.includes(\"jme\")) {\n", - " model.jme = notSubscribed;\n", - " }\n", - " if (!model.subscriptions.includes(\"smiles\")) {\n", - " model.smiles = notSubscribed;\n", - " }\n", - " if (!model.subscriptions.includes(\"mol\")) {\n", - " model.mol = notSubscribed;\n", - " }\n", - " if (!model.subscriptions.includes(\"mol3000\")) {\n", - " model.mol3000 = notSubscribed;\n", - " }\n", - " if (!model.subscriptions.includes(\"sdf\")) {\n", - " model.sdf = notSubscribed;\n", - " }\n", - " setModelValues(model, jsmeElement);\n", - " }\n", - " function cleanValue(value) {\n", - " if (value === null) {\n", - " return \"null\";\n", - " }\n", - " else {\n", - " return value;\n", - " }\n", - " }\n", - " function setOtherModelValues(model, jsmeElement) {\n", - " if (model.subscriptions.includes(\"jme\")) {\n", - " model.jme = cleanValue(jsmeElement.jmeFile());\n", - " }\n", - " if (model.subscriptions.includes(\"smiles\")) {\n", - " model.smiles = cleanValue(jsmeElement.smiles());\n", - " }\n", - " if (model.subscriptions.includes(\"mol\")) {\n", - " model.mol = cleanValue(jsmeElement.molFile(false));\n", - " }\n", - " if (model.subscriptions.includes(\"mol3000\")) {\n", - " model.mol3000 = cleanValue(jsmeElement.molFile(true));\n", - " }\n", - " if (model.subscriptions.includes(\"sdf\")) {\n", - " model.sdf = cleanValue(readSDFValue(jsmeElement));\n", - " }\n", - " }\n", - " // The view of the Bokeh extension/ HTML element\n", - " // Here you can define how to render the model as well as react to model changes or View events.\n", - " class JSMEEditorView extends layout_1.HTMLBoxView {\n", - " constructor() {\n", - " super(...arguments);\n", - " this.JSME = window.JSApplet.JSME;\n", - " this.valueChanging = true;\n", - " this._intialized = false;\n", - " }\n", - " initialize() {\n", - " super.initialize();\n", - " this.container = (0, dom_1.div)({\n", - " style: { display: \"contents\" }\n", - " });\n", - " }\n", - " connect_signals() {\n", - " super.connect_signals();\n", - " this.connect(this.model.properties.value.change, () => {\n", - " if (!this.valueChanging) {\n", - " if (this.model.value === \"\") {\n", - " this.jsmeElement.reset();\n", - " }\n", - " else {\n", - " this.jsmeElement.readGenericMolecularInput(this.model.value);\n", - " }\n", - " }\n", - " });\n", - " this.connect(this.model.properties.format.change, () => {\n", - " setModelValue(this.model, this.jsmeElement);\n", - " });\n", - " this.connect(this.model.properties.subscriptions.change, () => {\n", - " resetOtherModelValues(this.model, this.jsmeElement);\n", - " });\n", - " this.connect(this.model.properties.options.change, () => {\n", - " this.setJSMEOptions();\n", - " });\n", - " this.connect(this.model.properties.guicolor.change, () => {\n", - " this.setGUIColor();\n", - " });\n", - " }\n", - " render() {\n", - " super.render();\n", - " const id = \"jsme-\" + uuidv4();\n", - " const el = (0, dom_1.div)({\n", - " class: \"jsme-editor\",\n", - " id: id,\n", - " style: { width: \"100%\", height: \"100%\" }\n", - " });\n", - " this.container.appendChild(el);\n", - " this._intialized = false;\n", - " }\n", - " createJSMEElement() {\n", - " if (this._intialized)\n", - " return;\n", - " const id = this.container.children[0].id;\n", - " // Need to add it to document body for JSME to be able to find the id\n", - " document.body.appendChild(this.container);\n", - " this.jsmeElement = new this.JSME(id, this.getHeight(), this.getWidth(), {\n", - " \"options\": this.model.options.join(\",\"),\n", - " \"guicolor\": this.model.guicolor\n", - " });\n", - " this.jsmeElement.readGenericMolecularInput(this.model.value);\n", - " resetOtherModelValues(this.model, this.jsmeElement);\n", - " setModelValues(this.model, this.jsmeElement);\n", - " const this_ = this;\n", - " function showEvent(_) {\n", - " this_.valueChanging = true;\n", - " setModelValues(this_.model, this_.jsmeElement);\n", - " this_.valueChanging = false;\n", - " }\n", - " this.jsmeElement.setAfterStructureModifiedCallback(showEvent);\n", - " // Remove from document body and add to shadow DOM\n", - " document.body.removeChild(this.container);\n", - " this.shadow_el.appendChild(this.container);\n", - " this._intialized = true;\n", - " }\n", - " setGUIColor() {\n", - " this.jsmeElement.setUserInterfaceBackgroundColor(this.model.guicolor);\n", - " }\n", - " setJSMEOptions() {\n", - " const options = this.model.options.join(\",\");\n", - " this.jsmeElement.options(options);\n", - " }\n", - " getHeight() {\n", - " if ((this.model.sizing_mode === \"stretch_height\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.height) {\n", - " return this.el.style.height;\n", - " }\n", - " else if (this.model.height) {\n", - " return this.model.height.toString() + \"px\";\n", - " }\n", - " else {\n", - " return \"100px\";\n", - " }\n", - " }\n", - " getWidth() {\n", - " if ((this.model.sizing_mode === \"stretch_width\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.width) {\n", - " return this.el.style.width;\n", - " }\n", - " else if (this.model.width) {\n", - " return this.model.width.toString() + \"px\";\n", - " }\n", - " else {\n", - " return \"100px\";\n", - " }\n", - " }\n", - " resizeJSMEElement() {\n", - " this.jsmeElement.setSize(this.getWidth(), this.getHeight());\n", - " }\n", - " after_layout() {\n", - " super.after_layout();\n", - " this.createJSMEElement();\n", - " this.resizeJSMEElement();\n", - " }\n", - " }\n", - " exports.JSMEEditorView = JSMEEditorView;\n", - " JSMEEditorView.__name__ = \"JSMEEditorView\";\n", - " // The Bokeh .ts model corresponding to the Bokeh .py model\n", - " class JSMEEditor extends layout_1.HTMLBox {\n", - " constructor(attrs) {\n", - " super(attrs);\n", - " }\n", - " }\n", - " exports.JSMEEditor = JSMEEditor;\n", - " _a = JSMEEditor;\n", - " JSMEEditor.__name__ = \"JSMEEditor\";\n", - " JSMEEditor.__module__ = \"panel_chemistry.bokeh_extensions.jsme_editor\";\n", - " (() => {\n", - " _a.prototype.default_view = JSMEEditorView;\n", - " _a.define(({ String, Array }) => ({\n", - " value: [String, \"N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O\"],\n", - " format: [String, \"\"],\n", - " options: [Array(String), []],\n", - " jme: [String, \"\"],\n", - " smiles: [String, \"\"],\n", - " mol: [String, \"\"],\n", - " mol3000: [String, \"\"],\n", - " sdf: [String, \"\"],\n", - " subscriptions: [Array(String), []],\n", - " guicolor: [String, \"#c0c0c0\"],\n", - " }));\n", - " })();\n", - " },\n", - " \"fc768a0766\": /* bokeh_extensions/layout.js */ function _(require, module, exports, __esModule, __esExport) {\n", - " __esModule();\n", - " const types_1 = require(\"@bokehjs/core/util/types\");\n", - " const layout_dom_1 = require(\"@bokehjs/models/layouts/layout_dom\");\n", - " function set_size(el, model, adjustMargin = true) {\n", - " let width_policy = model.width != null ? \"fixed\" : \"fit\";\n", - " let height_policy = model.height != null ? \"fixed\" : \"fit\";\n", - " const { sizing_mode, margin } = model;\n", - " if (sizing_mode != null) {\n", - " if (sizing_mode == \"fixed\")\n", - " width_policy = height_policy = \"fixed\";\n", - " else if (sizing_mode == \"stretch_both\")\n", - " width_policy = height_policy = \"max\";\n", - " else if (sizing_mode == \"stretch_width\")\n", - " width_policy = \"max\";\n", - " else if (sizing_mode == \"stretch_height\")\n", - " height_policy = \"max\";\n", - " else {\n", - " switch (sizing_mode) {\n", - " case \"scale_width\":\n", - " width_policy = \"max\";\n", - " height_policy = \"min\";\n", - " break;\n", - " case \"scale_height\":\n", - " width_policy = \"min\";\n", - " height_policy = \"max\";\n", - " break;\n", - " case \"scale_both\":\n", - " width_policy = \"max\";\n", - " height_policy = \"max\";\n", - " break;\n", - " default:\n", - " throw new Error(\"unreachable\");\n", - " }\n", - " }\n", - " }\n", - " let wm, hm;\n", - " if (!adjustMargin) {\n", - " hm = wm = 0;\n", - " }\n", - " else if ((0, types_1.isArray)(margin)) {\n", - " if (margin.length === 4) {\n", - " hm = margin[0] + margin[2];\n", - " wm = margin[1] + margin[3];\n", - " }\n", - " else {\n", - " hm = margin[0] * 2;\n", - " wm = margin[1] * 2;\n", - " }\n", - " }\n", - " else if (margin == null) {\n", - " hm = wm = 0;\n", - " }\n", - " else {\n", - " wm = hm = margin * 2;\n", - " }\n", - " if (width_policy == \"fixed\" && model.width)\n", - " el.style.width = model.width + \"px\";\n", - " else if (width_policy == \"max\")\n", - " el.style.width = wm ? `calc(100% - ${wm}px)` : \"100%\";\n", - " if (model.min_width != null)\n", - " el.style.minWidth = model.min_width + \"px\";\n", - " if (model.max_width != null)\n", - " el.style.maxWidth = model.max_width + \"px\";\n", - " if (height_policy == \"fixed\" && model.height)\n", - " el.style.height = model.height + \"px\";\n", - " else if (height_policy == \"max\")\n", - " el.style.height = hm ? `calc(100% - ${hm}px)` : \"100%\";\n", - " if (model.min_height != null)\n", - " el.style.minHeight = model.min_height + \"px\";\n", - " if (model.max_width != null)\n", - " el.style.maxHeight = model.max_height + \"px\";\n", - " }\n", - " exports.set_size = set_size;\n", - " class HTMLBoxView extends layout_dom_1.LayoutDOMView {\n", - " render() {\n", - " super.render();\n", - " set_size(this.el, this.model);\n", - " }\n", - " get child_models() {\n", - " return [];\n", - " }\n", - " }\n", - " exports.HTMLBoxView = HTMLBoxView;\n", - " HTMLBoxView.__name__ = \"HTMLBoxView\";\n", - " class HTMLBox extends layout_dom_1.LayoutDOM {\n", - " constructor(attrs) {\n", - " super(attrs);\n", - " }\n", - " }\n", - " exports.HTMLBox = HTMLBox;\n", - " HTMLBox.__name__ = \"HTMLBox\";\n", - " },\n", - " \"516ed336e4\": /* bokeh_extensions/ngl_viewer.js */ function _(require, module, exports, __esModule, __esExport) {\n", - " __esModule();\n", - " const layout_1 = require(\"fc768a0766\") /* ./layout */;\n", - " class NGLViewerView extends layout_1.HTMLBoxView {\n", - " connect_signals() {\n", - " super.connect_signals();\n", - " this.connect(this.model.properties.object.change, this.updateStage);\n", - " this.connect(this.model.properties.extension.change, this.updateStage);\n", - " this.connect(this.model.properties.representation.change, this.updateStage);\n", - " this.connect(this.model.properties.color_scheme.change, this.updateParameters);\n", - " this.connect(this.model.properties.custom_color_scheme.change, this.updateParameters);\n", - " this.connect(this.model.properties.effect.change, this.updateEffect);\n", - " this.connect(this.model.properties.background_color.change, this.setBackgroundcolor);\n", - " }\n", - " render() {\n", - " super.render();\n", - " this.el.id = \"viewport\";\n", - " const wn = window;\n", - " const ngl = wn.NGL;\n", - " this._stage = new ngl.Stage(this.el);\n", - " this.setBackgroundcolor();\n", - " const stage = this._stage;\n", - " this.updateStage();\n", - " window.addEventListener(\"resize\", function () {\n", - " stage.handleResize();\n", - " }, false);\n", - " }\n", - " setBackgroundcolor() {\n", - " console.log(this.model.background_color);\n", - " this._stage.setParameters({ backgroundColor: this.model.background_color });\n", - " }\n", - " after_layout() {\n", - " super.after_layout();\n", - " this._stage.handleResize();\n", - " }\n", - " updateEffect() {\n", - " if (this.model.effect === \"spin\") {\n", - " this._stage.setSpin(true);\n", - " }\n", - " else if (this.model.effect === \"rock\") {\n", - " this._stage.setRock(true);\n", - " }\n", - " else {\n", - " this._stage.setSpin(false);\n", - " this._stage.setRock(false);\n", - " }\n", - " }\n", - " getParameters() {\n", - " if (this.model.color_scheme === \"custom\") {\n", - " var list = this.model.custom_color_scheme;\n", - " var scheme = NGL.ColormakerRegistry.addSelectionScheme(list, \"new scheme\");\n", - " return { color: scheme };\n", - " }\n", - " else {\n", - " return { colorScheme: this.model.color_scheme };\n", - " }\n", - " }\n", - " updateParameters() {\n", - " const parameters = this.getParameters();\n", - " try {\n", - " this._stage.compList[0].reprList[0].setParameters(parameters);\n", - " }\n", - " catch (e) {\n", - " console.log(e);\n", - " }\n", - " }\n", - " updateStage() {\n", - " const model = this.model;\n", - " this._stage.removeAllComponents();\n", - " if (model.object === \"\") {\n", - " return;\n", - " }\n", - " const parameters = this.getParameters();\n", - " function finish(o) {\n", - " o.addRepresentation(model.representation, parameters);\n", - " o.autoView();\n", - " }\n", - " if (model.extension !== \"\") {\n", - " this._stage.loadFile(new Blob([model.object], { type: 'text/plain' }), { ext: model.extension }).then(finish);\n", - " }\n", - " else if (model.object.includes(\"://\")) {\n", - " this._stage.loadFile(model.object).then(finish);\n", - " }\n", - " else {\n", - " this._stage.loadFile(\"rcsb://\" + model.object).then(finish);\n", - " }\n", - " // this.updateColor()\n", - " this.updateEffect();\n", - " }\n", - " }\n", - " exports.NGLViewerView = NGLViewerView;\n", - " NGLViewerView.__name__ = \"NGLViewerView\";\n", - " class NGLViewer extends layout_1.HTMLBox {\n", - " constructor(attrs) {\n", - " super(attrs);\n", - " }\n", - " static init_NGLViewer() {\n", - " this.prototype.default_view = NGLViewerView;\n", - " this.define(({ String, Any }) => ({\n", - " object: [String, \"\"],\n", - " extension: [String, \"\"],\n", - " background_color: [String, \"\"],\n", - " representation: [String, \"ribbon\"],\n", - " color_scheme: [String, \"chainid\"],\n", - " custom_color_scheme: [Any, \"chainid\"],\n", - " effect: [String, \"\"],\n", - " }));\n", - " this.override({\n", - " height: 400,\n", - " width: 600\n", - " });\n", - " }\n", - " }\n", - " exports.NGLViewer = NGLViewer;\n", - " NGLViewer.__name__ = \"NGLViewer\";\n", - " NGLViewer.__module__ = \"panel_chemistry.bokeh_extensions.ngl_viewer\";\n", - " },\n", - " }, \"82ab290c02\", {\"index\":\"82ab290c02\",\"bokeh_extensions/index\":\"86de82b1ae\",\"bokeh_extensions/jsme_editor\":\"001cd512a8\",\"bokeh_extensions/layout\":\"fc768a0766\",\"bokeh_extensions/ngl_viewer\":\"516ed336e4\"}, {});});\n", - " //# sourceMappingURL=panel_chemistry.js.map\n", - "\n", - " /* END panel_chemistry.js */\n", - " },\n", - "function(Bokeh) {} // ensure no trailing comma for IE\n", - " ];\n", - "\n", - " function run_inline_js() {\n", - " if ((root.Bokeh !== undefined) || (force === true)) {\n", - " for (var i = 0; i < inline_js.length; i++) {\n", - " inline_js[i].call(root, root.Bokeh);\n", - " }\n", - " // Cache old bokeh versions\n", - " if (Bokeh != undefined && !reloading) {\n", - "\tvar NewBokeh = root.Bokeh;\n", - "\tif (Bokeh.versions === undefined) {\n", - "\t Bokeh.versions = new Map();\n", - "\t}\n", - "\tif (NewBokeh.version !== Bokeh.version) {\n", - "\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", - "\t}\n", - "\troot.Bokeh = Bokeh;\n", - " }} else if (Date.now() < root._bokeh_timeout) {\n", - " setTimeout(run_inline_js, 100);\n", - " } else if (!root._bokeh_failed_load) {\n", - " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", - " root._bokeh_failed_load = true;\n", - " }\n", - " root._bokeh_is_initializing = false\n", - " }\n", - "\n", - " function load_or_wait() {\n", - " // Implement a backoff loop that tries to ensure we do not load multiple\n", - " // versions of Bokeh and its dependencies at the same time.\n", - " // In recent versions we use the root._bokeh_is_initializing flag\n", - " // to determine whether there is an ongoing attempt to initialize\n", - " // bokeh, however for backward compatibility we also try to ensure\n", - " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", - " // before older versions are fully initialized.\n", - " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", - " root._bokeh_is_initializing = false;\n", - " root._bokeh_onload_callbacks = undefined;\n", - " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", - " load_or_wait();\n", - " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", - " setTimeout(load_or_wait, 100);\n", - " } else {\n", - " Bokeh = root.Bokeh;\n", - " bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", - " root._bokeh_is_initializing = true\n", - " root._bokeh_onload_callbacks = []\n", - " if (!reloading && (!bokeh_loaded || is_dev)) {\n", - "\troot.Bokeh = undefined;\n", - " }\n", - " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", - "\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", - "\trun_inline_js();\n", - " });\n", - " }\n", - " }\n", - " // Give older versions of the autoload script a head-start to ensure\n", - " // they initialize before we start loading newer version.\n", - " setTimeout(load_or_wait, 100)\n", - "}(window));" - ], - "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.1/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsme.nocache.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.0.min.js\", \"https://cdn.holoviz.org/panel/1.3.1/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [\"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/mosaic.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/jsa.css\", \"https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/chrome.css\"];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n function(Bokeh) {\n /* BEGIN panel_chemistry.js */\n /*!\n * Copyright (c) 2012 - 2023, Anaconda, Inc., and Bokeh Contributors\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n * \n * Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n * \n * Neither the name of Anaconda nor the names of any contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n */\n (function(root, factory) {\n factory(root[\"Bokeh\"], undefined);\n })(this, function(Bokeh, version) {\n let define;\n return (function(modules, entry, aliases, externals) {\n const bokeh = typeof Bokeh !== \"undefined\" && (version != null ? Bokeh[version] : Bokeh);\n if (bokeh != null) {\n return bokeh.register_plugin(modules, entry, aliases);\n } else {\n throw new Error(\"Cannot find Bokeh \" + version + \". You have to load it prior to loading plugins.\");\n }\n })\n ({\n \"82ab290c02\": /* index.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n const tslib_1 = require(\"tslib\");\n const PanelChemistryExtensions = tslib_1.__importStar(require(\"86de82b1ae\") /* ./bokeh_extensions/ */);\n exports.PanelChemistryExtensions = PanelChemistryExtensions;\n const base_1 = require(\"@bokehjs/base\");\n (0, base_1.register_models)(PanelChemistryExtensions);\n },\n \"86de82b1ae\": /* bokeh_extensions/index.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n var jsme_editor_1 = require(\"001cd512a8\") /* ./jsme_editor */;\n __esExport(\"JSMEEditor\", jsme_editor_1.JSMEEditor);\n var ngl_viewer_1 = require(\"516ed336e4\") /* ./ngl_viewer */;\n __esExport(\"NGLViewer\", ngl_viewer_1.NGLViewer);\n },\n \"001cd512a8\": /* bokeh_extensions/jsme_editor.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n var _a;\n // See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html\n const layout_1 = require(\"fc768a0766\") /* ./layout */;\n const dom_1 = require(\"@bokehjs/core/dom\");\n function uuidv4() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n }\n const notSubscribed = \"Not Subscribed\";\n function readSDFValue(jsmeElement) {\n var data = jsmeElement.getMultiSDFstack();\n var output = \"No multirecords SDF was pasted into the editor \";\n if (data.length > 0) {\n output = data.join(\"$$$$\\n\") + \"$$$$\\n\";\n }\n return output;\n }\n function setModelValue(model, jsmeElement) {\n var value = model.value;\n if (model.format === \"smiles\") {\n value = jsmeElement.smiles();\n }\n else if (model.format === \"mol\") {\n value = jsmeElement.molFile(false);\n }\n else if (model.format === \"mol3000\") {\n value = jsmeElement.molFile(true);\n }\n else if (model.format === \"sdf\") {\n value = readSDFValue(jsmeElement);\n }\n else {\n value = jsmeElement.jmeFile();\n }\n if (model.value !== value && value !== null) {\n model.value = value;\n }\n }\n function setModelValues(model, jsmeElement) {\n setModelValue(model, jsmeElement);\n setOtherModelValues(model, jsmeElement);\n }\n function resetOtherModelValues(model, jsmeElement) {\n if (!model.subscriptions.includes(\"jme\")) {\n model.jme = notSubscribed;\n }\n if (!model.subscriptions.includes(\"smiles\")) {\n model.smiles = notSubscribed;\n }\n if (!model.subscriptions.includes(\"mol\")) {\n model.mol = notSubscribed;\n }\n if (!model.subscriptions.includes(\"mol3000\")) {\n model.mol3000 = notSubscribed;\n }\n if (!model.subscriptions.includes(\"sdf\")) {\n model.sdf = notSubscribed;\n }\n setModelValues(model, jsmeElement);\n }\n function cleanValue(value) {\n if (value === null) {\n return \"null\";\n }\n else {\n return value;\n }\n }\n function setOtherModelValues(model, jsmeElement) {\n if (model.subscriptions.includes(\"jme\")) {\n model.jme = cleanValue(jsmeElement.jmeFile());\n }\n if (model.subscriptions.includes(\"smiles\")) {\n model.smiles = cleanValue(jsmeElement.smiles());\n }\n if (model.subscriptions.includes(\"mol\")) {\n model.mol = cleanValue(jsmeElement.molFile(false));\n }\n if (model.subscriptions.includes(\"mol3000\")) {\n model.mol3000 = cleanValue(jsmeElement.molFile(true));\n }\n if (model.subscriptions.includes(\"sdf\")) {\n model.sdf = cleanValue(readSDFValue(jsmeElement));\n }\n }\n // The view of the Bokeh extension/ HTML element\n // Here you can define how to render the model as well as react to model changes or View events.\n class JSMEEditorView extends layout_1.HTMLBoxView {\n constructor() {\n super(...arguments);\n this.JSME = window.JSApplet.JSME;\n this.valueChanging = true;\n this._intialized = false;\n }\n initialize() {\n super.initialize();\n this.container = (0, dom_1.div)({\n style: { display: \"contents\" }\n });\n }\n connect_signals() {\n super.connect_signals();\n this.connect(this.model.properties.value.change, () => {\n if (!this.valueChanging) {\n if (this.model.value === \"\") {\n this.jsmeElement.reset();\n }\n else {\n this.jsmeElement.readGenericMolecularInput(this.model.value);\n }\n }\n });\n this.connect(this.model.properties.format.change, () => {\n setModelValue(this.model, this.jsmeElement);\n });\n this.connect(this.model.properties.subscriptions.change, () => {\n resetOtherModelValues(this.model, this.jsmeElement);\n });\n this.connect(this.model.properties.options.change, () => {\n this.setJSMEOptions();\n });\n this.connect(this.model.properties.guicolor.change, () => {\n this.setGUIColor();\n });\n }\n render() {\n super.render();\n const id = \"jsme-\" + uuidv4();\n const el = (0, dom_1.div)({\n class: \"jsme-editor\",\n id: id,\n style: { width: \"100%\", height: \"100%\" }\n });\n this.container.appendChild(el);\n this._intialized = false;\n }\n createJSMEElement() {\n if (this._intialized)\n return;\n const id = this.container.children[0].id;\n // Need to add it to document body for JSME to be able to find the id\n document.body.appendChild(this.container);\n this.jsmeElement = new this.JSME(id, this.getHeight(), this.getWidth(), {\n \"options\": this.model.options.join(\",\"),\n \"guicolor\": this.model.guicolor\n });\n this.jsmeElement.readGenericMolecularInput(this.model.value);\n resetOtherModelValues(this.model, this.jsmeElement);\n setModelValues(this.model, this.jsmeElement);\n const this_ = this;\n function showEvent(_) {\n this_.valueChanging = true;\n setModelValues(this_.model, this_.jsmeElement);\n this_.valueChanging = false;\n }\n this.jsmeElement.setAfterStructureModifiedCallback(showEvent);\n // Remove from document body and add to shadow DOM\n document.body.removeChild(this.container);\n this.shadow_el.appendChild(this.container);\n this._intialized = true;\n }\n setGUIColor() {\n this.jsmeElement.setUserInterfaceBackgroundColor(this.model.guicolor);\n }\n setJSMEOptions() {\n const options = this.model.options.join(\",\");\n this.jsmeElement.options(options);\n }\n getHeight() {\n if ((this.model.sizing_mode === \"stretch_height\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.height) {\n return this.el.style.height;\n }\n else if (this.model.height) {\n return this.model.height.toString() + \"px\";\n }\n else {\n return \"100px\";\n }\n }\n getWidth() {\n if ((this.model.sizing_mode === \"stretch_width\" || this.model.sizing_mode === \"stretch_both\") && this.el.style.width) {\n return this.el.style.width;\n }\n else if (this.model.width) {\n return this.model.width.toString() + \"px\";\n }\n else {\n return \"100px\";\n }\n }\n resizeJSMEElement() {\n this.jsmeElement.setSize(this.getWidth(), this.getHeight());\n }\n after_layout() {\n super.after_layout();\n this.createJSMEElement();\n this.resizeJSMEElement();\n }\n }\n exports.JSMEEditorView = JSMEEditorView;\n JSMEEditorView.__name__ = \"JSMEEditorView\";\n // The Bokeh .ts model corresponding to the Bokeh .py model\n class JSMEEditor extends layout_1.HTMLBox {\n constructor(attrs) {\n super(attrs);\n }\n }\n exports.JSMEEditor = JSMEEditor;\n _a = JSMEEditor;\n JSMEEditor.__name__ = \"JSMEEditor\";\n JSMEEditor.__module__ = \"panel_chemistry.bokeh_extensions.jsme_editor\";\n (() => {\n _a.prototype.default_view = JSMEEditorView;\n _a.define(({ String, Array }) => ({\n value: [String, \"N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O\"],\n format: [String, \"\"],\n options: [Array(String), []],\n jme: [String, \"\"],\n smiles: [String, \"\"],\n mol: [String, \"\"],\n mol3000: [String, \"\"],\n sdf: [String, \"\"],\n subscriptions: [Array(String), []],\n guicolor: [String, \"#c0c0c0\"],\n }));\n })();\n },\n \"fc768a0766\": /* bokeh_extensions/layout.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n const types_1 = require(\"@bokehjs/core/util/types\");\n const layout_dom_1 = require(\"@bokehjs/models/layouts/layout_dom\");\n function set_size(el, model, adjustMargin = true) {\n let width_policy = model.width != null ? \"fixed\" : \"fit\";\n let height_policy = model.height != null ? \"fixed\" : \"fit\";\n const { sizing_mode, margin } = model;\n if (sizing_mode != null) {\n if (sizing_mode == \"fixed\")\n width_policy = height_policy = \"fixed\";\n else if (sizing_mode == \"stretch_both\")\n width_policy = height_policy = \"max\";\n else if (sizing_mode == \"stretch_width\")\n width_policy = \"max\";\n else if (sizing_mode == \"stretch_height\")\n height_policy = \"max\";\n else {\n switch (sizing_mode) {\n case \"scale_width\":\n width_policy = \"max\";\n height_policy = \"min\";\n break;\n case \"scale_height\":\n width_policy = \"min\";\n height_policy = \"max\";\n break;\n case \"scale_both\":\n width_policy = \"max\";\n height_policy = \"max\";\n break;\n default:\n throw new Error(\"unreachable\");\n }\n }\n }\n let wm, hm;\n if (!adjustMargin) {\n hm = wm = 0;\n }\n else if ((0, types_1.isArray)(margin)) {\n if (margin.length === 4) {\n hm = margin[0] + margin[2];\n wm = margin[1] + margin[3];\n }\n else {\n hm = margin[0] * 2;\n wm = margin[1] * 2;\n }\n }\n else if (margin == null) {\n hm = wm = 0;\n }\n else {\n wm = hm = margin * 2;\n }\n if (width_policy == \"fixed\" && model.width)\n el.style.width = model.width + \"px\";\n else if (width_policy == \"max\")\n el.style.width = wm ? `calc(100% - ${wm}px)` : \"100%\";\n if (model.min_width != null)\n el.style.minWidth = model.min_width + \"px\";\n if (model.max_width != null)\n el.style.maxWidth = model.max_width + \"px\";\n if (height_policy == \"fixed\" && model.height)\n el.style.height = model.height + \"px\";\n else if (height_policy == \"max\")\n el.style.height = hm ? `calc(100% - ${hm}px)` : \"100%\";\n if (model.min_height != null)\n el.style.minHeight = model.min_height + \"px\";\n if (model.max_width != null)\n el.style.maxHeight = model.max_height + \"px\";\n }\n exports.set_size = set_size;\n class HTMLBoxView extends layout_dom_1.LayoutDOMView {\n render() {\n super.render();\n set_size(this.el, this.model);\n }\n get child_models() {\n return [];\n }\n }\n exports.HTMLBoxView = HTMLBoxView;\n HTMLBoxView.__name__ = \"HTMLBoxView\";\n class HTMLBox extends layout_dom_1.LayoutDOM {\n constructor(attrs) {\n super(attrs);\n }\n }\n exports.HTMLBox = HTMLBox;\n HTMLBox.__name__ = \"HTMLBox\";\n },\n \"516ed336e4\": /* bokeh_extensions/ngl_viewer.js */ function _(require, module, exports, __esModule, __esExport) {\n __esModule();\n const layout_1 = require(\"fc768a0766\") /* ./layout */;\n class NGLViewerView extends layout_1.HTMLBoxView {\n connect_signals() {\n super.connect_signals();\n this.connect(this.model.properties.object.change, this.updateStage);\n this.connect(this.model.properties.extension.change, this.updateStage);\n this.connect(this.model.properties.representation.change, this.updateStage);\n this.connect(this.model.properties.color_scheme.change, this.updateParameters);\n this.connect(this.model.properties.custom_color_scheme.change, this.updateParameters);\n this.connect(this.model.properties.effect.change, this.updateEffect);\n this.connect(this.model.properties.background_color.change, this.setBackgroundcolor);\n }\n render() {\n super.render();\n this.el.id = \"viewport\";\n const wn = window;\n const ngl = wn.NGL;\n this._stage = new ngl.Stage(this.el);\n this.setBackgroundcolor();\n const stage = this._stage;\n this.updateStage();\n window.addEventListener(\"resize\", function () {\n stage.handleResize();\n }, false);\n }\n setBackgroundcolor() {\n console.log(this.model.background_color);\n this._stage.setParameters({ backgroundColor: this.model.background_color });\n }\n after_layout() {\n super.after_layout();\n this._stage.handleResize();\n }\n updateEffect() {\n if (this.model.effect === \"spin\") {\n this._stage.setSpin(true);\n }\n else if (this.model.effect === \"rock\") {\n this._stage.setRock(true);\n }\n else {\n this._stage.setSpin(false);\n this._stage.setRock(false);\n }\n }\n getParameters() {\n if (this.model.color_scheme === \"custom\") {\n var list = this.model.custom_color_scheme;\n var scheme = NGL.ColormakerRegistry.addSelectionScheme(list, \"new scheme\");\n return { color: scheme };\n }\n else {\n return { colorScheme: this.model.color_scheme };\n }\n }\n updateParameters() {\n const parameters = this.getParameters();\n try {\n this._stage.compList[0].reprList[0].setParameters(parameters);\n }\n catch (e) {\n console.log(e);\n }\n }\n updateStage() {\n const model = this.model;\n this._stage.removeAllComponents();\n if (model.object === \"\") {\n return;\n }\n const parameters = this.getParameters();\n function finish(o) {\n o.addRepresentation(model.representation, parameters);\n o.autoView();\n }\n if (model.extension !== \"\") {\n this._stage.loadFile(new Blob([model.object], { type: 'text/plain' }), { ext: model.extension }).then(finish);\n }\n else if (model.object.includes(\"://\")) {\n this._stage.loadFile(model.object).then(finish);\n }\n else {\n this._stage.loadFile(\"rcsb://\" + model.object).then(finish);\n }\n // this.updateColor()\n this.updateEffect();\n }\n }\n exports.NGLViewerView = NGLViewerView;\n NGLViewerView.__name__ = \"NGLViewerView\";\n class NGLViewer extends layout_1.HTMLBox {\n constructor(attrs) {\n super(attrs);\n }\n static init_NGLViewer() {\n this.prototype.default_view = NGLViewerView;\n this.define(({ String, Any }) => ({\n object: [String, \"\"],\n extension: [String, \"\"],\n background_color: [String, \"\"],\n representation: [String, \"ribbon\"],\n color_scheme: [String, \"chainid\"],\n custom_color_scheme: [Any, \"chainid\"],\n effect: [String, \"\"],\n }));\n this.override({\n height: 400,\n width: 600\n });\n }\n }\n exports.NGLViewer = NGLViewer;\n NGLViewer.__name__ = \"NGLViewer\";\n NGLViewer.__module__ = \"panel_chemistry.bokeh_extensions.ngl_viewer\";\n },\n }, \"82ab290c02\", {\"index\":\"82ab290c02\",\"bokeh_extensions/index\":\"86de82b1ae\",\"bokeh_extensions/jsme_editor\":\"001cd512a8\",\"bokeh_extensions/layout\":\"fc768a0766\",\"bokeh_extensions/ngl_viewer\":\"516ed336e4\"}, {});});\n //# sourceMappingURL=panel_chemistry.js.map\n\n /* END panel_chemistry.js */\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "\n", - "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", - " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", - "}\n", - "\n", - "\n", - " function JupyterCommManager() {\n", - " }\n", - "\n", - " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", - " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", - " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", - " comm_manager.register_target(comm_id, function(comm) {\n", - " comm.on_msg(msg_handler);\n", - " });\n", - " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", - " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", - " comm.onMsg = msg_handler;\n", - " });\n", - " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", - " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", - " var messages = comm.messages[Symbol.asyncIterator]();\n", - " function processIteratorResult(result) {\n", - " var message = result.value;\n", - " console.log(message)\n", - " var content = {data: message.data, comm_id};\n", - " var buffers = []\n", - " for (var buffer of message.buffers || []) {\n", - " buffers.push(new DataView(buffer))\n", - " }\n", - " var metadata = message.metadata || {};\n", - " var msg = {content, buffers, metadata}\n", - " msg_handler(msg);\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " return messages.next().then(processIteratorResult);\n", - " })\n", - " }\n", - " }\n", - "\n", - " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", - " if (comm_id in window.PyViz.comms) {\n", - " return window.PyViz.comms[comm_id];\n", - " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", - " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", - " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", - " if (msg_handler) {\n", - " comm.on_msg(msg_handler);\n", - " }\n", - " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", - " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", - " comm.open();\n", - " if (msg_handler) {\n", - " comm.onMsg = msg_handler;\n", - " }\n", - " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", - " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", - " comm_promise.then((comm) => {\n", - " window.PyViz.comms[comm_id] = comm;\n", - " if (msg_handler) {\n", - " var messages = comm.messages[Symbol.asyncIterator]();\n", - " function processIteratorResult(result) {\n", - " var message = result.value;\n", - " var content = {data: message.data};\n", - " var metadata = message.metadata || {comm_id};\n", - " var msg = {content, metadata}\n", - " msg_handler(msg);\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " }) \n", - " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", - " return comm_promise.then((comm) => {\n", - " comm.send(data, metadata, buffers, disposeOnDone);\n", - " });\n", - " };\n", - " var comm = {\n", - " send: sendClosure\n", - " };\n", - " }\n", - " window.PyViz.comms[comm_id] = comm;\n", - " return comm;\n", - " }\n", - " window.PyViz.comm_manager = new JupyterCommManager();\n", - " \n", - "\n", - "\n", - "var JS_MIME_TYPE = 'application/javascript';\n", - "var HTML_MIME_TYPE = 'text/html';\n", - "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", - "var CLASS_NAME = 'output';\n", - "\n", - "/**\n", - " * Render data to the DOM node\n", - " */\n", - "function render(props, node) {\n", - " var div = document.createElement(\"div\");\n", - " var script = document.createElement(\"script\");\n", - " node.appendChild(div);\n", - " node.appendChild(script);\n", - "}\n", - "\n", - "/**\n", - " * Handle when a new output is added\n", - " */\n", - "function handle_add_output(event, handle) {\n", - " var output_area = handle.output_area;\n", - " var output = handle.output;\n", - " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", - " return\n", - " }\n", - " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", - " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", - " if (id !== undefined) {\n", - " var nchildren = toinsert.length;\n", - " var html_node = toinsert[nchildren-1].children[0];\n", - " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", - " var scripts = [];\n", - " var nodelist = html_node.querySelectorAll(\"script\");\n", - " for (var i in nodelist) {\n", - " if (nodelist.hasOwnProperty(i)) {\n", - " scripts.push(nodelist[i])\n", - " }\n", - " }\n", - "\n", - " scripts.forEach( function (oldScript) {\n", - " var newScript = document.createElement(\"script\");\n", - " var attrs = [];\n", - " var nodemap = oldScript.attributes;\n", - " for (var j in nodemap) {\n", - " if (nodemap.hasOwnProperty(j)) {\n", - " attrs.push(nodemap[j])\n", - " }\n", - " }\n", - " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", - " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", - " oldScript.parentNode.replaceChild(newScript, oldScript);\n", - " });\n", - " if (JS_MIME_TYPE in output.data) {\n", - " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", - " }\n", - " output_area._hv_plot_id = id;\n", - " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", - " window.PyViz.plot_index[id] = Bokeh.index[id];\n", - " } else {\n", - " window.PyViz.plot_index[id] = null;\n", - " }\n", - " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", - " var bk_div = document.createElement(\"div\");\n", - " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", - " var script_attrs = bk_div.children[0].attributes;\n", - " for (var i = 0; i < script_attrs.length; i++) {\n", - " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", - " }\n", - " // store reference to server id on output_area\n", - " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", - " }\n", - "}\n", - "\n", - "/**\n", - " * Handle when an output is cleared or removed\n", - " */\n", - "function handle_clear_output(event, handle) {\n", - " var id = handle.cell.output_area._hv_plot_id;\n", - " var server_id = handle.cell.output_area._bokeh_server_id;\n", - " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", - " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", - " if (server_id !== null) {\n", - " comm.send({event_type: 'server_delete', 'id': server_id});\n", - " return;\n", - " } else if (comm !== null) {\n", - " comm.send({event_type: 'delete', 'id': id});\n", - " }\n", - " delete PyViz.plot_index[id];\n", - " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", - " var doc = window.Bokeh.index[id].model.document\n", - " doc.clear();\n", - " const i = window.Bokeh.documents.indexOf(doc);\n", - " if (i > -1) {\n", - " window.Bokeh.documents.splice(i, 1);\n", - " }\n", - " }\n", - "}\n", - "\n", - "/**\n", - " * Handle kernel restart event\n", - " */\n", - "function handle_kernel_cleanup(event, handle) {\n", - " delete PyViz.comms[\"hv-extension-comm\"];\n", - " window.PyViz.plot_index = {}\n", - "}\n", - "\n", - "/**\n", - " * Handle update_display_data messages\n", - " */\n", - "function handle_update_output(event, handle) {\n", - " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", - " handle_add_output(event, handle)\n", - "}\n", - "\n", - "function register_renderer(events, OutputArea) {\n", - " function append_mime(data, metadata, element) {\n", - " // create a DOM node to render to\n", - " var toinsert = this.create_output_subarea(\n", - " metadata,\n", - " CLASS_NAME,\n", - " EXEC_MIME_TYPE\n", - " );\n", - " this.keyboard_manager.register_events(toinsert);\n", - " // Render to node\n", - " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", - " render(props, toinsert[0]);\n", - " element.append(toinsert);\n", - " return toinsert\n", - " }\n", - "\n", - " events.on('output_added.OutputArea', handle_add_output);\n", - " events.on('output_updated.OutputArea', handle_update_output);\n", - " events.on('clear_output.CodeCell', handle_clear_output);\n", - " events.on('delete.Cell', handle_clear_output);\n", - " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", - "\n", - " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", - " safe: true,\n", - " index: 0\n", - " });\n", - "}\n", - "\n", - "if (window.Jupyter !== undefined) {\n", - " try {\n", - " var events = require('base/js/events');\n", - " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", - " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", - " register_renderer(events, OutputArea);\n", - " }\n", - " } catch(err) {\n", - " }\n", - "}\n" - ], - "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "966119d9-2695-4cff-a96b-1b5cef13354e" - } - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "import panel as pn \n", "from panel_chemistry.widgets import JSMEEditor # panel_chemistry needs to be imported before you run pn.extension()\n", @@ -1194,101 +52,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "13bd929d-d3a5-4e2c-8c0b-492dc3e3d3d9", "metadata": {}, - "outputs": [ - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "Column(sizing_mode='stretch_width')\n", - " [0] JSMEEditor(format='smiles', height=500, sizing_mode='stretch_width', value='N[C@@H](CCC(=O)N[C@@H](CS...)\n", - " [1] TextInput(description='A value definining t..., name='Value', sizing_mode='stretch_width', value='N[C@@H](CCC(=O)N[C@@H](CS...)" - ] - }, - "execution_count": 2, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "42a8815b-483b-4ba6-9b66-1a5a030f34eb" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "smiles=\"N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O\"\n", "editor = JSMEEditor(value=smiles, height=500, format=\"smiles\")\n", @@ -1306,7 +73,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "97c39491-6796-42c6-a28a-05480dddb7de", "metadata": {}, "outputs": [], @@ -1323,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "fda4ce67-2e08-4dd1-8370-cc8b140880da", "metadata": {}, "outputs": [], @@ -1337,104 +104,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "f344ccb9-73ae-4797-b1a3-a40853270bce", "metadata": {}, - "outputs": [ - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "Row(sizing_mode='stretch_width')\n", - " [0] Column(sizing_mode='stretch_width')\n", - " [0] JSMEEditor(format='smiles', height=500, sizing_mode='stretch_width', value='20 19 N 2.42 0...)\n", - " [1] Param(JSMEEditor, parameters=['value', 'jme', ...], sizing_mode='stretch_width', widgets={'value': {'type': Date: Sun, 12 Nov 2023 19:43:24 +0000 Subject: [PATCH 07/11] remove smile --- src/panel_chemistry/bokeh_extensions/jsme_editor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts index b8ca803..8b1ae66 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts @@ -237,7 +237,7 @@ export class JSMEEditor extends HTMLBox { this.prototype.default_view = JSMEEditorView; this.define(({String, Array}) => ({ - value: [String, "N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O"], + value: [String, ""], format: [String, ""], options: [ Array(String), [] ], jme: [String, ""], From a877572ec7f66eef843959331a4e77b0a0d49423 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Sun, 12 Nov 2023 19:44:56 +0000 Subject: [PATCH 08/11] remove example --- src/panel_chemistry/bokeh_extensions/jsme_editor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.py b/src/panel_chemistry/bokeh_extensions/jsme_editor.py index fdbdc60..a1499ca 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.py +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.py @@ -21,7 +21,7 @@ class JSMEEditor(HTMLBox): # pylint: disable=too-few-public-methods,too-many-an "https://cdn.jsdelivr.net/npm/jsme-editor@2023.7.31/gwt/chrome/chrome.css", ] - value = String(default="N[C@@H](CCC(=O)N[C@@H](CS)C(=O)NCC(=O)O)C(=O)O") + value = String(default="") format = String(default="smiles") subscriptions = List(String, default=[]) # type: ignore options = List(String, default=[]) # type: ignore From 63b1ffe34be92d7df84d0186ed42a475109c932e Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Sun, 12 Nov 2023 19:47:45 +0000 Subject: [PATCH 09/11] use latest bokeh versions --- src/panel_chemistry/package-lock.json | 2 +- src/panel_chemistry/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panel_chemistry/package-lock.json b/src/panel_chemistry/package-lock.json index 279c583..84e63b4 100644 --- a/src/panel_chemistry/package-lock.json +++ b/src/panel_chemistry/package-lock.json @@ -9,7 +9,7 @@ "version": "0.3.0", "license": "Apache 2.0", "dependencies": { - "@bokeh/bokehjs": "~3.3.0" + "@bokeh/bokehjs": "~3.3.1" } }, "node_modules/@bokeh/bokehjs": { diff --git a/src/panel_chemistry/package.json b/src/panel_chemistry/package.json index d659260..e9d0a3e 100644 --- a/src/panel_chemistry/package.json +++ b/src/panel_chemistry/package.json @@ -5,6 +5,6 @@ "license": "Apache 2.0", "keywords": [], "dependencies": { - "@bokeh/bokehjs": "~3.3.0" + "@bokeh/bokehjs": "~3.3.1" } } From ef641ba547007ab293ed15a58e6af6b917359ddc Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Sun, 12 Nov 2023 20:05:03 +0000 Subject: [PATCH 10/11] minor improvements --- examples/reference/NGLViewer.ipynb | 5 +++-- src/panel_chemistry/bokeh_extensions/ngl_viewer.py | 12 ++++++------ src/panel_chemistry/bokeh_extensions/ngl_viewer.ts | 9 +++++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/reference/NGLViewer.ipynb b/examples/reference/NGLViewer.ipynb index 793f6ce..bde4304 100644 --- a/examples/reference/NGLViewer.ipynb +++ b/examples/reference/NGLViewer.ipynb @@ -176,7 +176,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -189,7 +189,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.11.6" } }, "nbformat": 4, diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py index b15adce..8bf28fd 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py @@ -7,13 +7,13 @@ class NGLViewer(LayoutDOM): # pylint: disable=too-many-ancestors """The [NGL Viewer](https://github.com/nglviewer/ngl) can be used to show and analyse pdb molecule structures""" - object = String() - background_color = String() - extension = String() - representation = String() - color_scheme = String() - effect = String() + object = String("") + extension = String("") + background_color = String("") + representation = String("ball+stick") + color_scheme = String("element") custom_color_scheme = List(List(String)) + effect = String("") __javascript__ = [ "https://unpkg.com/ngl@2.0.0-dev.37/dist/ngl.js", diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts index 0790ddf..310ed2c 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts @@ -189,6 +189,7 @@ export namespace NGLViewer { export interface NGLViewer extends NGLViewer.Attrs { } export class NGLViewer extends HTMLBox { properties: NGLViewer.Props + __view_type__: NGLViewerView constructor(attrs?: Partial) { super(attrs) @@ -196,16 +197,16 @@ export class NGLViewer extends HTMLBox { static __module__ = "panel_chemistry.bokeh_extensions.ngl_viewer" - static init_NGLViewer(): void { + static { this.prototype.default_view = NGLViewerView; this.define(({ String, Any }) => ({ object: [ String, ""], extension: [ String, ""], background_color: [ String, ""], - representation: [ String, "ribbon"], - color_scheme: [ String, "chainid"], - custom_color_scheme: [ Any, "chainid"], + representation: [ String, "ball+stick"], + color_scheme: [ String, "element"], + custom_color_scheme: [ Any, ["white", "*"]], effect: [ String, ""], })) From 25557ff9b2a64a59cd640bf1768d1cdc7f8dda22 Mon Sep 17 00:00:00 2001 From: MarcSkovMadsen Date: Sat, 25 Nov 2023 04:49:33 +0000 Subject: [PATCH 11/11] fix ngl_viewer --- pyproject.toml | 1 + script.py | 49 +++++++++++++++++++ .../bokeh_extensions/jsme_editor.py | 4 +- .../bokeh_extensions/jsme_editor.ts | 9 +--- .../bokeh_extensions/layout.ts | 7 +++ .../bokeh_extensions/ngl_viewer.py | 4 +- .../bokeh_extensions/ngl_viewer.ts | 40 ++++++++++++--- src/panel_chemistry/pane/ngl_viewer.py | 12 +---- 8 files changed, 96 insertions(+), 30 deletions(-) create mode 100644 script.py diff --git a/pyproject.toml b/pyproject.toml index 96b9b7b..85792ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,7 @@ module = [ "hvplot.*", "param", "py3Dmol", + "pydantic.*", "pyviz_comms", ] ignore_missing_imports = true diff --git a/script.py b/script.py new file mode 100644 index 0000000..f95a393 --- /dev/null +++ b/script.py @@ -0,0 +1,49 @@ +import panel as pn +from panel_chemistry.pane import NGLViewer # panel_chemistry needs to be imported before you run pn.extension() +from panel_chemistry.pane.ngl_viewer import EXTENSIONS + +pn.extension("ngl_viewer", sizing_mode="stretch_width") + +viewer = NGLViewer(object="1CRN", background_color="#F7F7F7", styles={"border": "1px solid lightgray"}, min_height=700, sizing_mode="stretch_both") + +settings = pn.Param( + viewer, + parameters=["object","extension","representation","color_scheme","custom_color_scheme","effect",], + name="⚙️ Settings" +) + +file_input = pn.widgets.FileInput(accept=','.join('.' + s for s in EXTENSIONS[1:])) + +def filename_callback(target, event): + target.extension = event.new.split('.')[1] + +def value_callback(target, event): + target.object = event.new.decode('utf-8') + +file_input.link(viewer, callbacks={'value': value_callback, 'filename': filename_callback}) + +header = pn.widgets.StaticText(value='{0}'.format("💾 File Input")) +file_column = pn.layout.Column(header, file_input) + +layout = pn.Param( + viewer, + parameters=["sizing_mode", "width", "height", "background_color"], + name="📐 Layout" +) + +pn.Row( + viewer, + pn.WidgetBox(settings, layout, width=300, sizing_mode="fixed",), +) + + +accent="#D2386C" + +pn.template.FastListTemplate( + site="Panel Chemistry", site_url="./", + title="NGLViewer", + sidebar=[file_column, settings, layout], + main=[viewer], + accent_base_color=accent, header_background=accent, +).servable(); + diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.py b/src/panel_chemistry/bokeh_extensions/jsme_editor.py index a1499ca..7cb2384 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.py +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.py @@ -23,8 +23,8 @@ class JSMEEditor(HTMLBox): # pylint: disable=too-few-public-methods,too-many-an value = String(default="") format = String(default="smiles") - subscriptions = List(String, default=[]) # type: ignore - options = List(String, default=[]) # type: ignore + subscriptions = List(String, default=[]) # type: ignore + options = List(String, default=[]) # type: ignore jme = String(default="") smiles = String(default="") diff --git a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts index 8b1ae66..64783b1 100644 --- a/src/panel_chemistry/bokeh_extensions/jsme_editor.ts +++ b/src/panel_chemistry/bokeh_extensions/jsme_editor.ts @@ -1,17 +1,10 @@ // See https://docs.bokeh.org/en/latest/docs/reference/models/layouts.html -import { HTMLBox, HTMLBoxView } from "./layout" +import { uuidv4, HTMLBox, HTMLBoxView } from "./layout" // See https://docs.bokeh.org/en/latest/docs/reference/core/properties.html import * as p from "@bokehjs/core/properties" import {div} from "@bokehjs/core/dom" -function uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - } - const notSubscribed = "Not Subscribed" function readSDFValue(jsmeElement: any) { diff --git a/src/panel_chemistry/bokeh_extensions/layout.ts b/src/panel_chemistry/bokeh_extensions/layout.ts index 7a0d8ea..cda8b97 100644 --- a/src/panel_chemistry/bokeh_extensions/layout.ts +++ b/src/panel_chemistry/bokeh_extensions/layout.ts @@ -2,6 +2,13 @@ import {isArray} from "@bokehjs/core/util/types" import {LayoutDOM, LayoutDOMView} from "@bokehjs/models/layouts/layout_dom" import * as p from "@bokehjs/core/properties" +export function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + export function set_size(el: HTMLElement, model: HTMLBox, adjustMargin: boolean = true): void { let width_policy = model.width != null ? "fixed" : "fit" let height_policy = model.height != null ? "fixed" : "fit" diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py index 8bf28fd..940b228 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.py +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.py @@ -16,7 +16,7 @@ class NGLViewer(LayoutDOM): # pylint: disable=too-many-ancestors effect = String("") __javascript__ = [ - "https://unpkg.com/ngl@2.0.0-dev.37/dist/ngl.js", + "https://unpkg.com/ngl@2.2.1/dist/ngl.js", ] __js_skip__ = { @@ -25,7 +25,7 @@ class NGLViewer(LayoutDOM): # pylint: disable=too-many-ancestors __js_require__ = { "paths": { - "NGL": "https://unpkg.com/ngl@2.0.0-dev.37/dist/ngl", + "NGL": "https://unpkg.com/ngl@2.2.1/dist/ngl", }, "exports": {"NGL": "NGL"}, } diff --git a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts index 310ed2c..826b8c3 100644 --- a/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts +++ b/src/panel_chemistry/bokeh_extensions/ngl_viewer.ts @@ -1,5 +1,6 @@ import * as p from "@bokehjs/core/properties" -import {HTMLBox, HTMLBoxView} from "./layout" +import {uuidv4, HTMLBox, HTMLBoxView} from "./layout" +import {div} from "@bokehjs/core/dom" declare namespace NGL { class AtomProxy{ @@ -86,8 +87,19 @@ declare namespace NGL { } export class NGLViewerView extends HTMLBoxView { model: NGLViewer + container: HTMLDivElement; + _intialized: boolean = false _stage: any + initialize(): void { + super.initialize() + this.container = div({ + class: "ngl-viewer", + id: "ngl-viewer-" + uuidv4(), + style: {width: "100%", height: "100%"} + }) + } + connect_signals(): void { super.connect_signals() this.connect(this.model.properties.object.change, this.updateStage) @@ -101,22 +113,34 @@ export class NGLViewerView extends HTMLBoxView { render(): void { super.render() - this.el.id = "viewport" + this._intialized = false + this.createNGLViewer() + } + setBackgroundcolor(): void { + this._stage.setParameters( { backgroundColor: this.model.background_color} ); + } + createNGLViewer(){ + if (this._intialized) + return + document.body.appendChild(this.container) + const wn = (window as any) const ngl = wn.NGL - - this._stage = new ngl.Stage(this.el); + + this._stage = new ngl.Stage(this.container.id); this.setBackgroundcolor() const stage = this._stage this.updateStage(); window.addEventListener( "resize", function(){ stage.handleResize(); }, false ); - } - setBackgroundcolor(): void { - console.log(this.model.background_color) - this._stage.setParameters( { backgroundColor: this.model.background_color} ); + + // Remove from document body and add to shadow DOM + document.body.removeChild(this.container) + this.shadow_el.appendChild(this.container) + + this._intialized = true } after_layout(): void { super.after_layout() diff --git a/src/panel_chemistry/pane/ngl_viewer.py b/src/panel_chemistry/pane/ngl_viewer.py index addbd42..7ab361c 100644 --- a/src/panel_chemistry/pane/ngl_viewer.py +++ b/src/panel_chemistry/pane/ngl_viewer.py @@ -96,10 +96,11 @@ class NGLViewer(PaneBase): # pylint: disable=too-many-ancestors to show and analyse pdb molecule structures""" object = param.String( + default="", doc=""" The object to display. For example an url like 'rcsb://3dqb.pdb', 'rcsb://1NKT', '1NKT'. You can also specify a extension string if you define the extension - in the extension parameter""" + in the extension parameter""", ) background_color = param.Color( doc=""" @@ -163,15 +164,6 @@ def _get_model(self, doc, root=None, parent=None, comm=None): props["object"] = self.object model = _NGLViewer(**props) root = root or model - # self._link_props( - # model, - # [ - # "event", - # ], - # doc, - # root, - # comm, - # ) self._models[root.ref["id"]] = (model, parent) return model