diff --git a/deploy/pip_packages.txt b/deploy/pip_packages.txt index 072ee55b79698a77ffeba02a516fb3b8aac82a7b..7a73488bfd813fe1d25e561033afda97971c65e0 100644 --- a/deploy/pip_packages.txt +++ b/deploy/pip_packages.txt @@ -20,6 +20,7 @@ pytest-django==2.8.0 factory_boy mock==1.0.1 py==1.4.29 +django.js==0.8.1 django-jenkins==0.17.0 diff --git a/django/website/hid/migrations/0001_initial.py b/django/website/hid/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..635bfc9ca1173c34256bcdfd7a4dbcc8ae4e89de --- /dev/null +++ b/django/website/hid/migrations/0001_initial.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +def create_sample_widgets(apps, schema_editor): + Dashboard = apps.get_model('dashboard', 'Dashboard') + WidgetInstance = apps.get_model('dashboard', 'WidgetInstance') + main = Dashboard.objects.get(name='main') + WidgetInstance.objects.create( + dashboard=main, + widget_type='basic-text-widget', + row=0, + column=0, + width=6, + height='small', + settings={ + 'title': 'Sample title', + 'text': 'Sample text' + } + ) + WidgetInstance.objects.create( + dashboard=main, + widget_type='basic-text-widget', + row=0, + column=1, + width=6, + height='small', + settings={ + 'title': 'Another title', + 'text': 'Another text' + } + ) + WidgetInstance.objects.create( + dashboard=main, + widget_type='basic-text-widget', + row=1, + column=1, + width=6, + height='medium', + settings={ + 'title': 'Yes antoher widget title', + 'text': 'Yet another text' + } + ) + WidgetInstance.objects.create( + dashboard=main, + widget_type='question-chart-widget', + row=1, + column=0, + width=6, + height='medium', + settings={ + 'name': 'a chart', + 'questions': { + 'question three': 23, + 'question one': 10, + 'question four': 150, + 'question two': 50 + } + } + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ('dashboard', '0002_auto_20150709_1244') + ] + + operations = [ + migrations.RunPython(create_sample_widgets) + ] diff --git a/django/website/hid/static/hid/widgets/chart.js b/django/website/hid/static/hid/widgets/chart.js index 061668cf222362f802bed4717d72fde1ba99f4b5..54b79baf93dab1b670af46f59ff50b0849856a0c 100644 --- a/django/website/hid/static/hid/widgets/chart.js +++ b/django/website/hid/static/hid/widgets/chart.js @@ -1,3 +1,7 @@ +FlotChart = { + models: [], + views: [] +}; (function($) { /** * FlotChart model @@ -6,7 +10,7 @@ * single flot chart. * */ - var FlotChart = Backbone.Model.extend({ + FlotChart.model = Backbone.Model.extend({ defaults: { data: [], options: {} @@ -18,7 +22,7 @@ * * Displays a single FlotChart model */ - var FlotChartView = Backbone.View.extend({ + FlotChart.view = Backbone.View.extend({ /* Create the view */ initialize: function(options) { this.chart = options.chart; @@ -58,12 +62,15 @@ this.$tooltip = null; } if (item) { - this.$tooltip = $('<div>' + item.datapoint[0] + '</div>'); - this.$tooltip.css({ - position: 'absolute', - top: item.pageY - 10, - left: item.pageX + 10 - }).appendTo('body').fadeIn('fast'); + this.$tooltip = $('<div>'); + this.$tooltip.html(item.datapoint[0]) + .addClass('flot-chart-tooltip') + .css({ + position: 'absolute', + top: item.pageY - 10, + left: item.pageX + 10 + }); + this.$tooltip.appendTo('body').fadeIn('fast'); } } }); @@ -77,14 +84,17 @@ * data: flot data * options: flot options */ - $(document).ready(function() { + FlotChart.initialize = function() { $('.flot-chart').each(function() { - var flot_chart = new FlotChart($(this).data()); - var flot_chart_view = new FlotChartView({ + var flot_chart = new FlotChart.model($(this).data()); + var flot_chart_view = new FlotChart.view({ el: this, chart: flot_chart }); flot_chart_view.render(); + FlotChart.models.push(flot_chart); + FlotChart.views.push(flot_chart_view); }); - }); + }; })(jQuery); +jQuery(document).ready(FlotChart.initialize); diff --git a/django/website/hid/templates/hid/tests/chart.html b/django/website/hid/templates/hid/tests/chart.html new file mode 100644 index 0000000000000000000000000000000000000000..b4e4ca77c639110551fb4fc59570b1abdc5a1879 --- /dev/null +++ b/django/website/hid/templates/hid/tests/chart.html @@ -0,0 +1,59 @@ +{% extends "djangojs/qunit-runner.html" %} +{% block js_content %} + <script> + QUnit.test('Models and views are created', function(assert) { + assert.equal(1, FlotChart.models.length); + assert.equal(1, FlotChart.views.length); + }); + + QUnit.test('Model is created from the data attributes', function(assert) { + assert.deepEqual(FlotChart.models[0].get('data'), [[[23, 0], [10, 1], [150, 2], [50, 3]]]); + assert.deepEqual(FlotChart.models[0].get('options'), { + 'series': { + 'bars': { + 'show': true + } + }, + 'bars': { + 'horizontal': true + }, + 'yaxis': { + 'ticks': [[0, "q1"], [1, "q2"], [2, "q3"], [3, "q4"]] + } + }); + }); + + QUnit.test('Tooltip method adds tooltip to page', function(assert) { + assert.equal(jQuery('.flot-chart-tooltip').length, 0); + FlotChart.views[0].tooltip(null, null, { + datapoint: [1234], + pageY: 10, + pageX: 10 + }); + assert.equal(jQuery('.flot-chart-tooltip').length, 1); + // Ensure the tooltip is removed + FlotChart.views[0].tooltip(null, null, null); + }); + + QUnit.test('Tooltip html contains data point', function(assert) { + FlotChart.views[0].tooltip(null, null, { + datapoint: [1234], + pageY: 10, + pageX: 10 + }); + assert.equal(jQuery('.flot-chart-tooltip').html(), '1234'); + // Ensure the tooltip is removed + FlotChart.views[0].tooltip(null, null, null); + }); + QUnit.test('Canvas is created on page', function(assert) { + assert.ok(jQuery('.flot-chart canvas').length > 0); + }); + </script> +{% endblock %} +{% block body_content %} + <div class='flot-chart' + data-data='[[[23, 0], [10, 1], [150, 2], [50, 3]]]' + data-options='{"series": {"bars": {"show": true}}, "bars": {"horizontal": true}, "yaxis": {"ticks": [[0, "q1"], [1, "q2"], [2, "q3"], [3, "q4"]]}}' + style='width:300px; height:300px' + ></div> +{% endblock %} diff --git a/django/website/hid/templatetags/json_data.py b/django/website/hid/templatetags/json_data.py index 80553c75c25b2ddde870f3923c8fd2601921b6b0..6b40f0fe64289ae0c5d9e54b29db488080d67a0d 100644 --- a/django/website/hid/templatetags/json_data.py +++ b/django/website/hid/templatetags/json_data.py @@ -9,4 +9,4 @@ def json_data(value): """ Django custom template tag used to embed arbitrary values as json within html5 data- attributes. """ - return json.dumps(value).replace("'", "\\'") + return json.dumps(value) diff --git a/django/website/hid/tests/chart_javascript_tests.py b/django/website/hid/tests/chart_javascript_tests.py new file mode 100644 index 0000000000000000000000000000000000000000..0244b3f9265f6eaed77cd4f63a1e312e07c89ef2 --- /dev/null +++ b/django/website/hid/tests/chart_javascript_tests.py @@ -0,0 +1,13 @@ +from djangojs.runners import QUnitSuite, JsTemplateTestCase + + +class ChartJavascriptTest(QUnitSuite, JsTemplateTestCase): + template_name = 'hid/tests/chart.html' + js_files = ( + 'js/jquery.min.js', + 'js/underscore.js', + 'js/backbone.js', + 'flot/jquery.flot.js', + 'flot/jquery.flot.resize.js', + 'hid/widgets/chart.js' + ) diff --git a/django/website/local_settings.py.dev b/django/website/local_settings.py.dev index 3f141b468ece868617e6cc78e667dbc4aed7afc4..41f2337f35ac927b4bd491fd08ae9df5d0fc0eaa 100644 --- a/django/website/local_settings.py.dev +++ b/django/website/local_settings.py.dev @@ -7,6 +7,7 @@ DEBUG = True TEMPLATE_DEBUG = DEBUG ASSETS_DEBUG = DEBUG ASSETS_AUTO_BUILD = DEBUG +DJANGOJS_DEBUG = DEBUG # used in admin template so we know which site we're looking at DEPLOY_ENV = "localdev" @@ -22,7 +23,7 @@ DATABASES = { 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 'PORT': '', # Set to empty string for default. Not used with sqlite3. 'OPTIONS': { - "init_command": "SET storage_engine=INNODB;", + "init_command": "SET storage_engine=INNODB;SET foreign_key_checks = 0;", } } } diff --git a/django/website/settings.py b/django/website/settings.py index f6c0b5a1f18c65db373e72237e51376705d8a8f6..2d614e42492cfbcd50989bcf9685b71ef68c7252 100644 --- a/django/website/settings.py +++ b/django/website/settings.py @@ -134,6 +134,7 @@ THIRD_PARTY_APPS = ( 'bootstrap3', 'rest_framework', 'django_tables2', + 'djangojs' ) LOCAL_APPS = ( diff --git a/django/website/urls.py b/django/website/urls.py index a1f7900c4337d2f693c689d30e764ce47254d075..06bf03ec58eeb0d4bc1b2671aa49c52cc69f5333 100644 --- a/django/website/urls.py +++ b/django/website/urls.py @@ -38,5 +38,5 @@ if settings.DEBUG: url(r'^favicon.ico$', RedirectView.as_view( url='{0}images/favicon.ico'.format(settings.STATIC_URL), permanent=True - )), + )) ) + urlpatterns