diff --git a/ckanext/reclinepreview/plugin.py b/ckanext/reclinepreview/plugin.py index 826227b1d16..21f695eb0e3 100644 --- a/ckanext/reclinepreview/plugin.py +++ b/ckanext/reclinepreview/plugin.py @@ -1,36 +1,84 @@ from logging import getLogger +from ckan.common import json import ckan.plugins as p import ckan.plugins.toolkit as toolkit log = getLogger(__name__) +ignore_missing = p.toolkit.get_validator('ignore_missing') +natural_number_validator = p.toolkit.get_validator('natural_number_validator') -class ReclinePreview(p.SingletonPlugin): - """This extension previews resources using recline - - This extension implements two interfaces - - - ``IConfigurer`` allows to modify the configuration - - ``IResourcePreview`` allows to add previews - """ +class ReclineView(p.SingletonPlugin): + ''' + This base class for the Recline view extensions. + ''' p.implements(p.IConfigurer, inherit=True) - p.implements(p.IResourcePreview, inherit=True) + p.implements(p.IResourceView, inherit=True) + + # schema fields that apply to all Recline views + schema = {'offset': [ignore_missing, natural_number_validator], + 'limit': [ignore_missing, natural_number_validator]} def update_config(self, config): - ''' Set up the resource library, public directory and + ''' + Set up the resource library, public directory and template directory for the preview ''' toolkit.add_public_directory(config, 'theme/public') toolkit.add_template_directory(config, 'theme/templates') toolkit.add_resource('theme/public', 'ckanext-reclinepreview') - def can_preview(self, data_dict): - # if the resource is in the datastore then we can preview it with recline + def can_view(self, data_dict): if data_dict['resource'].get('datastore_active'): return True - format_lower = data_dict['resource']['format'].lower() - return format_lower in ['csv', 'xls', 'tsv'] + return False + + def setup_template_variables(self, context, data_dict): + return {'resource_json': json.dumps(data_dict['resource']), + 'resource_view_json': json.dumps(data_dict['resource_view'])} + + def view_template(self, context, data_dict): + return 'recline_view.html' + + +class ReclineGrid(ReclineView): + ''' + This extension views resources using a Recline grid. + ''' + + def info(self): + return {'name': 'recline_grid', + 'title': 'Grid', + 'schema': self.schema} + + def form_template(self, context, data_dict): + return 'recline_grid_form.html' + + +class ReclineGraph(ReclineView): + ''' + This extension views resources using a Recline graph. + ''' + + def info(self): + return {'name': 'recline_graph', + 'title': 'Graph', + 'schema': self.schema} + + def form_template(self, context, data_dict): + return 'recline_graph_form.html' + + +class ReclineMap(ReclineView): + ''' + This extension views resources using a Recline map. + ''' + + def info(self): + return {'name': 'recline_map', + 'title': 'Map', + 'schema': self.schema} - def preview_template(self, context, data_dict): - return 'recline.html' + def form_template(self, context, data_dict): + return 'recline_map_form.html' diff --git a/ckanext/reclinepreview/theme/public/preview_recline.js b/ckanext/reclinepreview/theme/public/preview_recline.js index 2f291469fed..6e8071c2314 100644 --- a/ckanext/reclinepreview/theme/public/preview_recline.js +++ b/ckanext/reclinepreview/theme/public/preview_recline.js @@ -3,10 +3,10 @@ this.ckan.module('reclinepreview', function (jQuery, _) { return { options: { i18n: { - errorLoadingPreview: "Could not load preview", + errorLoadingPreview: "Could not load view", errorDataProxy: "DataProxy returned an error", errorDataStore: "DataStore returned an error", - previewNotAvailableForDataType: "Preview not available for data type: " + previewNotAvailableForDataType: "View not available for data type: " }, site_url: "" }, @@ -19,19 +19,10 @@ this.ckan.module('reclinepreview', function (jQuery, _) { }, _onReady: function() { - this.loadPreviewDialog(preload_resource); + this.loadView(preload_resource, preload_resource_view); }, - // **Public: Loads a data preview** - // - // Fetches the preview data object from the link provided and loads the - // parsed data from the webstore displaying it in the most appropriate - // manner. - // - // link - Preview button. - // - // Returns nothing. - loadPreviewDialog: function (resourceData) { + loadView: function (resourceData, reclineView) { var self = this; function showError(msg){ @@ -39,15 +30,6 @@ this.ckan.module('reclinepreview', function (jQuery, _) { window.parent.ckan.pubsub.publish('data-viewer-error', msg); } - recline.Backend.DataProxy.timeout = 10000; - // will no be necessary any more with https://github.com/okfn/recline/pull/345 - recline.Backend.DataProxy.dataproxy_url = '//jsonpdataproxy.appspot.com'; - - // 2 situations - // a) something was posted to the datastore - need to check for this - // b) csv or xls (but not datastore) - resourceData.formatNormalized = this.normalizeFormat(resourceData.format); - resourceData.url = this.normalizeUrl(resourceData.url); if (resourceData.formatNormalized === '') { var tmp = resourceData.url.split('/'); @@ -62,96 +44,50 @@ this.ckan.module('reclinepreview', function (jQuery, _) { var errorMsg, dataset; - if (resourceData.datastore_active) { - resourceData.backend = 'ckan'; - // Set endpoint of the resource to the datastore api (so it can locate - // CKAN DataStore) - resourceData.endpoint = jQuery('body').data('site-root') + 'api'; - dataset = new recline.Model.Dataset(resourceData); - errorMsg = this.options.i18n.errorLoadingPreview + ': ' + this.options.i18n.errorDataStore; - dataset.fetch() - .done(function(dataset){ - self.initializeDataExplorer(dataset); - }) - .fail(function(error){ - if (error.message) errorMsg += ' (' + error.message + ')'; - showError(errorMsg); - }); + resourceData.backend = 'ckan'; + resourceData.endpoint = jQuery('body').data('site-root') + 'api'; - } else if (resourceData.formatNormalized in {'csv': '', 'xls': ''}) { - // set format as this is used by Recline in setting format for DataProxy - resourceData.format = resourceData.formatNormalized; - resourceData.backend = 'dataproxy'; - dataset = new recline.Model.Dataset(resourceData); - errorMsg = this.options.i18n.errorLoadingPreview + ': ' +this.options.i18n.errorDataProxy; - dataset.fetch() - .done(function(dataset){ - dataset.bind('query:fail', function (error) { - jQuery('.data-view-container', self.el).hide(); - jQuery('.header', self.el).hide(); - }); + dataset = new recline.Model.Dataset(resourceData); + dataset.query({ + "from": reclineView.offset || 0, + "size": reclineView.limit || 100 + }); - self.initializeDataExplorer(dataset); - }) - .fail(function(error){ - if (error.message) errorMsg += ' (' + error.message + ')'; - showError(errorMsg); - }); - } + errorMsg = this.options.i18n.errorLoadingPreview + ': ' + this.options.i18n.errorDataStore; + dataset.fetch() + .done(function(dataset){ + self.initializeView(dataset, reclineView); + }) + .fail(function(error){ + if (error.message) errorMsg += ' (' + error.message + ')'; + showError(errorMsg); + }); }, - initializeDataExplorer: function (dataset) { - var views = [ - { - id: 'grid', - label: 'Grid', - view: new recline.View.SlickGrid({ - model: dataset - }) - }, - { - id: 'graph', - label: 'Graph', - view: new recline.View.Graph({ - model: dataset - }) - }, - { - id: 'map', - label: 'Map', - view: new recline.View.Map({ - model: dataset - }) - } - ]; - - var sidebarViews = [ - { - id: 'valueFilter', - label: 'Filters', - view: new recline.View.ValueFilter({ - model: dataset - }) - } - ]; + initializeView: function (dataset, reclineView) { + var view; - var dataExplorer = new recline.View.MultiView({ - el: this.el, - model: dataset, - views: views, - sidebarViews: sidebarViews, - config: { - readOnly: true - } - }); + if(reclineView.view_type === "recline_graph") { + view = new recline.View.Graph({ + model: dataset, + el: this.el + }); + } else if(reclineView.view_type == "recline_map") { + view = new recline.View.Map({ + model: dataset, + el: this.el + }); + } else { + view = new recline.View.SlickGrid({ + model: dataset, + el: this.el + }); + } + view.visible = true; + view.render(); }, - normalizeFormat: function (format) { - var out = format.toLowerCase(); - out = out.split('/'); - out = out[out.length-1]; - return out; - }, + normalizeUrl: function (url) { if (url.indexOf('https') === 0) { return 'http' + url.slice(5); diff --git a/ckanext/reclinepreview/theme/templates/recline_graph_form.html b/ckanext/reclinepreview/theme/templates/recline_graph_form.html new file mode 100644 index 00000000000..d4fb0bd9429 --- /dev/null +++ b/ckanext/reclinepreview/theme/templates/recline_graph_form.html @@ -0,0 +1,4 @@ +{% import 'macros/form.html' as form %} + +{{ form.input('offset', id='field-offset', label=_('Row offset'), placeholder=_('eg: 0'), value=data.offset, error=errors.offset, classes=['control-medium']) }} +{{ form.input('limit', id='field-limit', label=_('Number of rows'), placeholder=_('eg: 100'), value=data.limit, error=errors.limit, classes=['control-medium']) }} diff --git a/ckanext/reclinepreview/theme/templates/recline_grid_form.html b/ckanext/reclinepreview/theme/templates/recline_grid_form.html new file mode 100644 index 00000000000..d4fb0bd9429 --- /dev/null +++ b/ckanext/reclinepreview/theme/templates/recline_grid_form.html @@ -0,0 +1,4 @@ +{% import 'macros/form.html' as form %} + +{{ form.input('offset', id='field-offset', label=_('Row offset'), placeholder=_('eg: 0'), value=data.offset, error=errors.offset, classes=['control-medium']) }} +{{ form.input('limit', id='field-limit', label=_('Number of rows'), placeholder=_('eg: 100'), value=data.limit, error=errors.limit, classes=['control-medium']) }} diff --git a/ckanext/reclinepreview/theme/templates/recline_map_form.html b/ckanext/reclinepreview/theme/templates/recline_map_form.html new file mode 100644 index 00000000000..82925d69c7b --- /dev/null +++ b/ckanext/reclinepreview/theme/templates/recline_map_form.html @@ -0,0 +1,5 @@ +{% import 'macros/form.html' as form %} + +{{ form.input('offset', id='field-offset', label=_('Row offset'), placeholder=_('eg: 0'), value=data.offset, error=errors.offset, classes=['control-medium']) }} +{{ form.input('limit', id='field-limit', label=_('Number of rows'), placeholder=_('eg: 100'), value=data.limit, error=errors.limit, classes=['control-medium']) }} + diff --git a/ckanext/reclinepreview/theme/templates/recline.html b/ckanext/reclinepreview/theme/templates/recline_view.html similarity index 52% rename from ckanext/reclinepreview/theme/templates/recline.html rename to ckanext/reclinepreview/theme/templates/recline_view.html index 852b6936b01..59f02539f6c 100644 --- a/ckanext/reclinepreview/theme/templates/recline.html +++ b/ckanext/reclinepreview/theme/templates/recline_view.html @@ -1,4 +1,4 @@ -{% extends "dataviewer/base.html" %} +{% extends "base.html" %} {% block page %}
@@ -9,4 +9,14 @@

{% resource 'ckanext-reclinepreview/main' %} -{% endblock %} \ No newline at end of file +{% endblock %} + +{% block scripts %} + +{% endblock %} + +{% block styles %}{% endblock %} +{% block custom_styles %}{% endblock %} diff --git a/setup.py b/setup.py index 77e6b92c60b..50f9b097e58 100644 --- a/setup.py +++ b/setup.py @@ -120,7 +120,9 @@ resource_proxy=ckanext.resourceproxy.plugin:ResourceProxy text_preview=ckanext.textpreview.plugin:TextPreview pdf_preview=ckanext.pdfpreview.plugin:PdfPreview - recline_preview=ckanext.reclinepreview.plugin:ReclinePreview + recline_grid=ckanext.reclinepreview.plugin:ReclineGrid + recline_graph=ckanext.reclinepreview.plugin:ReclineGraph + recline_map=ckanext.reclinepreview.plugin:ReclineMap example_itemplatehelpers=ckanext.example_itemplatehelpers.plugin:ExampleITemplateHelpersPlugin example_idatasetform=ckanext.example_idatasetform.plugin:ExampleIDatasetFormPlugin example_iauthfunctions_v1=ckanext.example_iauthfunctions.plugin_v1:ExampleIAuthFunctionsPlugin