diff --git a/.gitignore b/.gitignore index 60f5f651..b3455323 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ qgrid/static/ # OS X .DS_Store + +# Compiled javascript +qgrid/nbextension/ +qgrid/labextension/ \ No newline at end of file diff --git a/install.json b/install.json new file mode 100644 index 00000000..f4e2d954 --- /dev/null +++ b/install.json @@ -0,0 +1,5 @@ +{ + "packageManager": "python", + "packageName": "qgrid", + "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package qgrid" +} \ No newline at end of file diff --git a/js/.eslintignore b/js/.eslintignore new file mode 100644 index 00000000..5c99ba78 --- /dev/null +++ b/js/.eslintignore @@ -0,0 +1,5 @@ +node_modules +dist +coverage +**/*.d.ts +tests diff --git a/js/.eslintrc.js b/js/.eslintrc.js new file mode 100644 index 00000000..d66148c1 --- /dev/null +++ b/js/.eslintrc.js @@ -0,0 +1,39 @@ +module.exports = { + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:prettier/recommended' + ], + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + sourceType: 'module' + }, + plugins: ['@typescript-eslint'], + rules: { + '@typescript-eslint/naming-convention': [ + 'error', + { + 'selector': 'interface', + 'format': ['PascalCase'], + 'custom': { + 'regex': '^I[A-Z]', + 'match': true + } + } + ], + '@typescript-eslint/no-unused-vars': ['warn', { args: 'none' }], + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/quotes': [ + 'error', + 'single', + { avoidEscape: true, allowTemplateLiterals: false } + ], + curly: ['error', 'all'], + eqeqeq: 'error', + 'prefer-arrow-callback': 'error' + } +}; diff --git a/js/LICENSE b/js/LICENSE new file mode 100644 index 00000000..9091a521 --- /dev/null +++ b/js/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2020, Quantopian Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/js/src/embed.js b/js/lib/embed.js similarity index 85% rename from js/src/embed.js rename to js/lib/embed.js index b3f3ea2c..1556a47b 100644 --- a/js/src/embed.js +++ b/js/lib/embed.js @@ -6,4 +6,4 @@ // Export widget models and views, and the npm package version number. module.exports = require('./qgrid.widget.js'); -module.exports.version = require('../package.json').version; +module.exports['version'] = require('../package.json').version; diff --git a/js/lib/example.js b/js/lib/example.js new file mode 100644 index 00000000..7eac0f4f --- /dev/null +++ b/js/lib/example.js @@ -0,0 +1,55 @@ +var widgets = require('@jupyter-widgets/base'); +var _ = require('lodash'); + +// See example.py for the kernel counterpart to this file. + + +// Custom Model. Custom widgets models must at least provide default values +// for model attributes, including +// +// - `_view_name` +// - `_view_module` +// - `_view_module_version` +// +// - `_model_name` +// - `_model_module` +// - `_model_module_version` +// +// when different from the base class. + +// When serialiazing the entire widget state for embedding, only values that +// differ from the defaults will be specified. +var HelloModel = widgets.DOMWidgetModel.extend({ + defaults: _.extend(widgets.DOMWidgetModel.prototype.defaults(), { + _model_name : 'HelloModel', + _view_name : 'HelloView', + _model_module : 'qgrid2', + _view_module : 'qgrid2', + _model_module_version : '2.0.0', + _view_module_version : '2.0.0', + value : 'Hello World!' + }) +}); + + +// Custom View. Renders the widget model. +var HelloView = widgets.DOMWidgetView.extend({ + // Defines how the widget gets rendered into the DOM + render: function() { + this.value_changed(); + + // Observe changes in the value traitlet in Python, and define + // a custom callback. + this.model.on('change:value', this.value_changed, this); + }, + + value_changed: function() { + this.el.textContent = this.model.get('value'); + } +}); + + +module.exports = { + HelloModel: HelloModel, + HelloView: HelloView +}; diff --git a/js/src/extension.js b/js/lib/extension.js similarity index 57% rename from js/src/extension.js rename to js/lib/extension.js index 21eca77a..7f43363b 100644 --- a/js/src/extension.js +++ b/js/lib/extension.js @@ -1,13 +1,19 @@ // This file contains the javascript that is run when the notebook is loaded. // It contains some requirejs configuration and the `load_ipython_extension` // which is required for any notebook extension. +// +// Some static assets may be required by the custom widget javascript. The base +// url for the notebook is not known at build time and is therefore computed +// dynamically. +__webpack_public_path__ = document.querySelector('body').getAttribute('data-base-url') + 'nbextensions/qgrid2'; + // Configure requirejs if (window.require) { window.require.config({ map: { "*" : { - "qgrid": "nbextensions/qgrid/index" + "qgrid2": "nbextensions/qgrid2/index", } } }); diff --git a/js/lib/index.js b/js/lib/index.js new file mode 100644 index 00000000..d7c97015 --- /dev/null +++ b/js/lib/index.js @@ -0,0 +1,3 @@ +// Export widget models and views, and the npm package version number. +module.exports = require('./qgrid.widget.js'); +module.exports['version'] = require('../package.json').version; diff --git a/js/src/jupyterlab-plugin.js b/js/lib/labplugin.js similarity index 53% rename from js/src/jupyterlab-plugin.js rename to js/lib/labplugin.js index 4a48955f..21bec3df 100644 --- a/js/src/jupyterlab-plugin.js +++ b/js/lib/labplugin.js @@ -1,19 +1,16 @@ -var qgrid = require('./index'); - +var plugin = require('./index'); var base = require('@jupyter-widgets/base'); -/** - * The widget manager provider. - */ module.exports = { - id: 'qgrid', + id: 'qgrid2:plugin', requires: [base.IJupyterWidgetRegistry], activate: function(app, widgets) { widgets.registerWidget({ - name: 'qgrid', - version: qgrid.version, - exports: qgrid + name: 'qgrid2', + version: plugin.version, + exports: plugin }); - }, + }, autoStart: true }; + diff --git a/js/src/qgrid.booleanfilter.js b/js/lib/qgrid.booleanfilter.js similarity index 100% rename from js/src/qgrid.booleanfilter.js rename to js/lib/qgrid.booleanfilter.js diff --git a/js/src/qgrid.css b/js/lib/qgrid.css similarity index 100% rename from js/src/qgrid.css rename to js/lib/qgrid.css diff --git a/js/src/qgrid.datefilter.js b/js/lib/qgrid.datefilter.js similarity index 100% rename from js/src/qgrid.datefilter.js rename to js/lib/qgrid.datefilter.js diff --git a/js/src/qgrid.editors.js b/js/lib/qgrid.editors.js similarity index 100% rename from js/src/qgrid.editors.js rename to js/lib/qgrid.editors.js diff --git a/js/src/qgrid.filterbase.js b/js/lib/qgrid.filterbase.js similarity index 100% rename from js/src/qgrid.filterbase.js rename to js/lib/qgrid.filterbase.js diff --git a/js/src/qgrid.sliderfilter.js b/js/lib/qgrid.sliderfilter.js similarity index 100% rename from js/src/qgrid.sliderfilter.js rename to js/lib/qgrid.sliderfilter.js diff --git a/js/src/qgrid.textfilter.js b/js/lib/qgrid.textfilter.js similarity index 100% rename from js/src/qgrid.textfilter.js rename to js/lib/qgrid.textfilter.js diff --git a/js/src/qgrid.widget.js b/js/lib/qgrid.widget.js similarity index 95% rename from js/src/qgrid.widget.js rename to js/lib/qgrid.widget.js index 7c5efd37..6ff24fbd 100644 --- a/js/src/qgrid.widget.js +++ b/js/lib/qgrid.widget.js @@ -7,13 +7,6 @@ var slider_filter = require('./qgrid.sliderfilter.js'); var text_filter = require('./qgrid.textfilter.js'); var boolean_filter = require('./qgrid.booleanfilter.js'); var editors = require('./qgrid.editors.js'); -var dialog = null; -try { - dialog = require('base/js/dialog'); -} catch (e) { - console.warn("Qgrid was unable to load base/js/dialog. " + - "Full screen button won't be available"); -} var jquery_ui = require('jquery-ui-dist/jquery-ui.min.js'); require('slickgrid-qgrid/slick.core.js'); @@ -36,8 +29,8 @@ class QgridModel extends widgets.DOMWidgetModel { _view_name : 'QgridView', _model_module : 'qgrid', _view_module : 'qgrid', - _model_module_version : '^1.1.3', - _view_module_version : '^1.1.3', + _model_module_version : '^1.0.0', + _view_module_version : '^1.0.0', _df_json: '', _columns: {} }); @@ -116,30 +109,6 @@ class QgridView extends widgets.DOMWidgetView { this.buttons.tooltip('disable'); this.full_screen_btn = null; - if (dialog) { - this.full_screen_modal = $('body').find('.qgrid-modal'); - if (this.full_screen_modal.length == 0) { - this.full_screen_modal = $(` - - `).appendTo($('body')); - } - this.full_screen_btn = $(` -