diff --git a/forest/__init__.py b/forest/__init__.py
index 8633fd20f..cac220c47 100644
--- a/forest/__init__.py
+++ b/forest/__init__.py
@@ -23,7 +23,7 @@
.. automodule:: forest.presets
"""
-__version__ = '0.16.1'
+__version__ = '0.16.2'
from .config import *
from . import (
diff --git a/forest/js/forest.js b/forest/js/forest.js
new file mode 100644
index 000000000..1903ce248
--- /dev/null
+++ b/forest/js/forest.js
@@ -0,0 +1,19 @@
+const helloWorld = () => "Hello, World!"
+
+
+// Populate variable options from dataset value
+const link_selects = function(dataset_select, variable_select, source) {
+ let label = dataset_select.value;
+ if (label !== "") {
+ let index = source.data['datasets'].indexOf(label)
+ let defaults = ["Please specify"];
+ variable_select.options = defaults.concat(
+ source.data['variables'][index]);
+ }
+}
+
+
+module.exports = {
+ helloWorld,
+ link_selects
+}
diff --git a/forest/js/forest.test.js b/forest/js/forest.test.js
new file mode 100644
index 000000000..53f395103
--- /dev/null
+++ b/forest/js/forest.test.js
@@ -0,0 +1,8 @@
+const forest = require("./forest")
+
+
+describe("helloWorld", () => {
+ it("should return message", () => {
+ expect(forest.helloWorld()).toEqual("Hello, World!")
+ })
+})
diff --git a/forest/js/main.js b/forest/js/main.js
new file mode 100644
index 000000000..48c9f9722
--- /dev/null
+++ b/forest/js/main.js
@@ -0,0 +1,2 @@
+window.forest = require('./forest')
+
diff --git a/forest/js/package.json b/forest/js/package.json
new file mode 100644
index 000000000..6113c6fb4
--- /dev/null
+++ b/forest/js/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "forestjs",
+ "version": "0.0.1",
+ "description": "Helper JS for FOREST Python library",
+ "main": "index.js",
+ "dependencies": {
+ "redux": "^4.0.5"
+ },
+ "devDependencies": {
+ "browserify": "^16.5.1",
+ "jest": "^26.0.1"
+ },
+ "scripts": {
+ "test": "jest",
+ "watch": "jest --watch ./*.test.js",
+ "build": "browserify main.js -o ../static/forest-min.js"
+ },
+ "author": "andrewgryan",
+ "license": "BSD-3-Clause"
+}
diff --git a/forest/static/script.js b/forest/static/script.js
index e619344c2..06a4d886f 100644
--- a/forest/static/script.js
+++ b/forest/static/script.js
@@ -4,20 +4,3 @@ let openId = function(id) {
let closeId = function(id) {
document.getElementById(id).style.width = "0";
}
-
-let forest = (function() {
- let ns = {};
-
- // Populate variable options from dataset value
- ns.link_selects = function(dataset_select, variable_select, source) {
- let label = dataset_select.value;
- if (label !== "") {
- let index = source.data['datasets'].indexOf(label)
- let defaults = ["Please specify"];
- variable_select.options = defaults.concat(
- source.data['variables'][index]);
- }
- }
-
- return ns;
-})();
diff --git a/forest/templates/index.html b/forest/templates/index.html
index 5301696cc..38351dcf9 100644
--- a/forest/templates/index.html
+++ b/forest/templates/index.html
@@ -14,6 +14,7 @@
{% block postamble %}
+
{% endblock %}
{% block contents %}
diff --git a/requirements.txt b/requirements.txt
index 3692acdce..7e6bf95cd 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
bokeh>=2.0.1 # Port to 2.0.0 in future
+nodejs>=10.13
datashader
h5netcdf
iris
diff --git a/setup.py b/setup.py
index c3246daac..1c4c6b9ca 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,11 @@
"""
import os
import re
+import subprocess
import setuptools
+import setuptools.command.build_py
+import setuptools.command.develop
+import setuptools.command.install
NAME = "forest"
@@ -27,11 +31,57 @@ def load(fname):
return result
+def build_js(command_subclass):
+ """Decorator to call npm install and npm run build"""
+ subclass_run = command_subclass.run
+ def run(self):
+ self.run_command("build_js")
+ subclass_run(self)
+ command_subclass.run = run
+ return command_subclass
+
+
+@build_js
+class InstallCommand(setuptools.command.install.install):
+ """Python and JS code"""
+
+
+@build_js
+class DevelopCommand(setuptools.command.develop.develop):
+ """Python and JS code"""
+
+
+@build_js
+class BuildPyCommand(setuptools.command.build_py.build_py):
+ """Python and JS code"""
+
+
+class BuildJSCommand(setuptools.command.build_py.build_py):
+ """Use nodejs and npm commands to browserify forest.js
+
+ .. note:: Assume current working directory is package ROOT
+ """
+ def run(self):
+ cwd = os.getcwd()
+ os.chdir("forest/js")
+ if not os.path.exists("node_modules"):
+ subprocess.check_call(["npm", "install"])
+ subprocess.check_call(["npm", "run", "build"])
+ os.chdir(cwd)
+ super().run()
+
+
setuptools.setup(
name=NAME,
version=find_version(),
author="Andrew Ryan",
author_email="andrew.ryan@metoffice.gov.uk",
+ cmdclass={
+ "install": InstallCommand,
+ "develop": DevelopCommand,
+ "build_py": BuildPyCommand,
+ "build_js": BuildJSCommand,
+ },
description="Forecast visualisation and survey tool",
packages=setuptools.find_packages(),
package_data={
diff --git a/test/test_js.py b/test/test_js.py
new file mode 100644
index 000000000..0b897dcfe
--- /dev/null
+++ b/test/test_js.py
@@ -0,0 +1,12 @@
+import os
+import subprocess
+
+
+JS_DIR = os.path.join(os.path.dirname(__file__), "../forest/js")
+
+
+def test_forestjs():
+ cwd = os.getcwd()
+ os.chdir(JS_DIR)
+ subprocess.check_call(["npm", "test"])
+ os.chdir(cwd)