diff --git a/ckan/config/deployment.ini_tmpl b/ckan/config/deployment.ini_tmpl
index ca717788f02..53ddc80c108 100644
--- a/ckan/config/deployment.ini_tmpl
+++ b/ckan/config/deployment.ini_tmpl
@@ -82,7 +82,7 @@ ckan.site_id = default
# Add ``pdf_preview`` to enable the resource preview for PDFs
# Add ``resource_proxy`` to enable resorce proxying and get around the
# same origin policy
-ckan.plugins = stats json_preview recline_preview
+ckan.plugins = stats text_preview recline_preview
## Front-End Settings
diff --git a/ckan/lib/datapreview.py b/ckan/lib/datapreview.py
index 9d93d794fdd..27e7804bc83 100644
--- a/ckan/lib/datapreview.py
+++ b/ckan/lib/datapreview.py
@@ -11,8 +11,10 @@
import ckan.plugins as p
-DEFAULT_DIRECT_EMBED = ['png', 'jpg', 'gif']
-DEFAULT_LOADABLE_IFRAME = ['html', 'htm', 'rdf+xml', 'owl+xml', 'xml', 'n3', 'n-triples', 'turtle', 'plain', 'atom', 'rss', 'txt']
+DEFAULT_DIRECT_EMBED = ['png', 'jpg', 'jpeg', 'gif']
+DEFAULT_LOADABLE_IFRAME = ['html', 'htm', 'rdf+xml', 'owl+xml', 'xml',
+ 'n3', 'n-triples', 'turtle', 'plain',
+ 'atom', 'rss', 'txt']
def compare_domains(urls):
diff --git a/ckan/lib/helpers.py b/ckan/lib/helpers.py
index b82be9d20cf..76a9eb6c888 100644
--- a/ckan/lib/helpers.py
+++ b/ckan/lib/helpers.py
@@ -1504,7 +1504,8 @@ def resource_preview(resource, pkg_id):
reason = None
if format_lower:
log.info(
- _(u'No preview handler for resource of type {0}'.format(format_lower))
+ _(u'No preview handler for resource of type {0}'.format(
+ format_lower))
)
else:
reason = _(u'The resource format is not specified.')
diff --git a/ckan/tests/test_coding_standards.py b/ckan/tests/test_coding_standards.py
index aab479fe166..34bd996f9dd 100644
--- a/ckan/tests/test_coding_standards.py
+++ b/ckan/tests/test_coding_standards.py
@@ -250,9 +250,7 @@ class TestImportFromCkan(object):
'ckan/tests/test_plugins.py',
'ckan/tests/test_wsgi_ckanclient.py',
'ckan/websetup.py',
- 'ckanext/jsonpreview/tests/test_preview.py',
'ckanext/multilingual/plugin.py',
- 'ckanext/pdfpreview/tests/test_preview.py',
'ckanext/reclinepreview/tests/test_preview.py',
'ckanext/stats/controller.py',
'ckanext/stats/stats.py',
@@ -761,12 +759,9 @@ class TestPep8(object):
'ckanext/datastore/tests/test_upsert.py',
'ckanext/example_idatasetform/plugin.py',
'ckanext/example_itemplatehelpers/plugin.py',
- 'ckanext/jsonpreview/plugin.py',
- 'ckanext/jsonpreview/tests/test_preview.py',
'ckanext/multilingual/plugin.py',
'ckanext/multilingual/tests/test_multilingual_plugin.py',
'ckanext/pdfpreview/plugin.py',
- 'ckanext/pdfpreview/tests/test_preview.py',
'ckanext/reclinepreview/plugin.py',
'ckanext/reclinepreview/tests/test_preview.py',
'ckanext/resourceproxy/controller.py',
diff --git a/ckanext/jsonpreview/plugin.py b/ckanext/jsonpreview/plugin.py
deleted file mode 100644
index 37b471b215c..00000000000
--- a/ckanext/jsonpreview/plugin.py
+++ /dev/null
@@ -1,59 +0,0 @@
-from logging import getLogger
-
-import ckan.plugins as p
-
-log = getLogger(__name__)
-
-proxy = False
-try:
- import ckanext.resourceproxy.plugin as proxy
-except ImportError:
- pass
-
-
-class JsonPreview(p.SingletonPlugin):
- """This extension previews JSON(P)
-
- This extension implements two interfaces
-
- - ``IConfigurer`` allows to modify the configuration
- - ``IConfigurable`` get the configuration
- - ``IResourcePreview`` allows to add previews
- """
- p.implements(p.IConfigurer, inherit=True)
- p.implements(p.IConfigurable, inherit=True)
- p.implements(p.IResourcePreview, inherit=True)
-
- JSON_FORMATS = ['json']
- JSONP_FORMATS = ['jsonp']
- proxy_is_enabled = False
-
- def update_config(self, config):
- ''' Set up the resource library, public directory and
- template directory for the preview
- '''
- p.toolkit.add_public_directory(config, 'theme/public')
- p.toolkit.add_template_directory(config, 'theme/templates')
- p.toolkit.add_resource('theme/public', 'ckanext-jsonpreview')
-
- def configure(self, config):
- self.proxy_is_enabled = config.get('ckan.resource_proxy_enabled', False)
-
- def can_preview(self, data_dict):
- resource = data_dict['resource']
- format_lower = resource['format'].lower()
- if format_lower in self.JSONP_FORMATS:
- return True
- elif format_lower in self.JSON_FORMATS and (self.proxy_is_enabled or resource['on_same_domain']):
- return True
- return False
-
- def setup_template_variables(self, context, data_dict):
- assert self.can_preview(data_dict)
- resource = data_dict['resource']
- format_lower = resource['format'].lower()
- if format_lower in self.JSON_FORMATS and self.proxy_is_enabled and not resource['on_same_domain']:
- p.toolkit.c.resource['url'] = proxy.get_proxified_resource_url(data_dict)
-
- def preview_template(self, context, data_dict):
- return 'json.html'
diff --git a/ckanext/jsonpreview/theme/public/css/json.css b/ckanext/jsonpreview/theme/public/css/json.css
deleted file mode 100644
index 7ef8f90a457..00000000000
--- a/ckanext/jsonpreview/theme/public/css/json.css
+++ /dev/null
@@ -1,33 +0,0 @@
-body {
- width: 500px;
-}
-
-pre {
- font-size: 13px;
-}
-
-.loading {
- font-weight: bold;
- font-family: sans-serif;
- font-size: 16px;
- position: fixed;
- left: -20px;
- top: 20px;
-}
-
-.string {
- color: #009900;
-}
-.number {
- color: #0066FF;
-}
-.boolean {
- color: #E62E00;
-}
-.null {
- color: #E62E00;
-}
-.key {
- color: #222;
- font-weight: bold;
-}
\ No newline at end of file
diff --git a/ckanext/jsonpreview/theme/public/preview_json.js b/ckanext/jsonpreview/theme/public/preview_json.js
deleted file mode 100644
index 0d6175ef830..00000000000
--- a/ckanext/jsonpreview/theme/public/preview_json.js
+++ /dev/null
@@ -1,50 +0,0 @@
-// json preview module
-ckan.module('jsonpreview', function (jQuery, _) {
- return {
- options: {
- i18n: {
- error: _('An error occurred: %(text)s %(error)s')
- }
- },
- initialize: function () {
- var self = this;
- jQuery.ajax(preload_resource['url'], {
- type: 'GET',
- async: false,
- contentType: "application/json",
- dataType: preload_resource['format'],
- success: function(data, textStatus, jqXHR) {
- var html = JSON.stringify(data, null, 4);
- var pretty = self._syntaxHighlight(html);
- self.el.html(pretty);
- },
- error: function(jqXHR, textStatus, errorThrown) {
- self.el.html(self.i18n('error', {text: textStatus, error: errorThrown}));
- }
- });
- },
-
- // from: http://stackoverflow.com/a/7220510/214950
- _syntaxHighlight: function(json) {
- if (typeof json != 'string') {
- json = JSON.stringify(json, undefined, 2);
- }
- json = json.replace(/&/g, '&').replace(//g, '>');
- return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
- var cls = 'number';
- if (/^"/.test(match)) {
- if (/:$/.test(match)) {
- cls = 'key';
- } else {
- cls = 'string';
- }
- } else if (/true|false/.test(match)) {
- cls = 'boolean';
- } else if (/null/.test(match)) {
- cls = 'null';
- }
- return '' + match + '';
- });
- }
- };
-});
\ No newline at end of file
diff --git a/ckanext/jsonpreview/theme/public/resource.config b/ckanext/jsonpreview/theme/public/resource.config
deleted file mode 100644
index 91aa72ed365..00000000000
--- a/ckanext/jsonpreview/theme/public/resource.config
+++ /dev/null
@@ -1,10 +0,0 @@
-[depends]
-
-main = base/main
-
-[groups]
-
-main =
- preview_json.js
-
- css/json.css
diff --git a/ckanext/jsonpreview/theme/templates/json.html b/ckanext/jsonpreview/theme/templates/json.html
deleted file mode 100644
index a9a241944ff..00000000000
--- a/ckanext/jsonpreview/theme/templates/json.html
+++ /dev/null
@@ -1,13 +0,0 @@
-{% extends 'dataviewer/base.html' %}
-
-{% block page %}
-
-
-
- {{ _('Loading...') }}
-
-
-
-
- {% resource 'ckanext-jsonpreview/main' %}
-{% endblock %}
\ No newline at end of file
diff --git a/ckanext/pdfpreview/tests/test_preview.py b/ckanext/pdfpreview/tests/test_preview.py
index b2d0931a3b3..fb6aa643332 100644
--- a/ckanext/pdfpreview/tests/test_preview.py
+++ b/ckanext/pdfpreview/tests/test_preview.py
@@ -9,8 +9,8 @@
import ckan.plugins as plugins
import ckan.lib.helpers as h
import ckanext.pdfpreview.plugin as previewplugin
-from ckan.lib.create_test_data import CreateTestData
-from ckan.config.middleware import make_app
+import ckan.lib.create_test_data as create_test_data
+import ckan.config.middleware as middleware
class TestPdfPreview(tests.WsgiAppCase):
@@ -19,13 +19,12 @@ class TestPdfPreview(tests.WsgiAppCase):
def setup_class(cls):
cls._original_config = config.copy()
config['ckan.plugins'] = 'pdf_preview'
- wsgiapp = make_app(config['global_conf'], **config)
+ wsgiapp = middleware.make_app(config['global_conf'], **config)
cls.app = paste.fixture.TestApp(wsgiapp)
cls.p = previewplugin.PdfPreview()
- # create test resource
- CreateTestData.create()
+ create_test_data.CreateTestData.create()
context = {
'model': model,
@@ -34,8 +33,10 @@ def setup_class(cls):
}
cls.package = model.Package.get('annakarenina')
- cls.resource = logic.get_action('resource_show')(context, {'id': cls.package.resources[1].id})
- cls.resource['url'] = pylons.config.get('ckan.site_url', '//localhost:5000')
+ cls.resource = logic.get_action('resource_show')(
+ context, {'id': cls.package.resources[1].id})
+ cls.resource['url'] = pylons.config.get(
+ 'ckan.site_url', '//localhost:5000')
cls.resource['format'] = 'pdf'
logic.action.update.resource_update(context, cls.resource)
@@ -44,7 +45,7 @@ def teardown_class(cls):
config.clear()
config.update(cls._original_config)
plugins.reset()
- CreateTestData.delete()
+ create_test_data.CreateTestData.delete()
def test_can_preview(self):
data_dict = {
@@ -86,12 +87,14 @@ def test_js_included(self):
result = self.app.get(url, status='*')
assert result.status == 200, result.status
- assert (('preview_pdf.js' in result.body) or ('preview_pdf.min.js' in result.body))
+ assert (('preview_pdf.js' in result.body) or (
+ 'preview_pdf.min.js' in result.body))
assert 'preload_resource' in result.body
assert 'data-module="pdfpreview"' in result.body
def test_iframe_is_shown(self):
- url = h.url_for(controller='package', action='resource_read', id=self.package.name, resource_id=self.resource['id'])
+ url = h.url_for(controller='package', action='resource_read',
+ id=self.package.name, resource_id=self.resource['id'])
result = self.app.get(url)
assert 'data-module="data-viewer"' in result.body
assert '/gm,">")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=(""+o.nodeName.toLowerCase()+">")}while(o!=u.node);r.splice(q,1);while(q'+L[0]+""}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return''+r.value+""}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+=""}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"
")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.javascript=function(a){return{k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const",literal:"true false null undefined NaN Infinity"},c:[a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,{cN:"regexp",b:"/",e:"/[gim]*",i:"\\n",c:[{b:"\\\\/"}]},{b:"<",e:">;",sL:"xml"}],r:0},{cN:"function",bWK:true,e:"{",k:"function",c:[{cN:"title",b:"[A-Za-z$_][0-9A-Za-z$_]*"},{cN:"params",b:"\\(",e:"\\)",c:[a.CLCM,a.CBLCLM],i:"[\"'\\(]"}],i:"\\[|%"}]}}(hljs);hljs.LANGUAGES.xml=function(a){var c="[A-Za-z0-9\\._:-]+";var b={eW:true,c:[{cN:"attribute",b:c,r:0},{b:'="',rB:true,e:'"',c:[{cN:"value",b:'"',eW:true}]},{b:"='",rB:true,e:"'",c:[{cN:"value",b:"'",eW:true}]},{b:"=",c:[{cN:"value",b:"[^\\s/>]+"}]}]};return{cI:true,c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"",rE:true,sL:"css"}},{cN:"tag",b:"
+ {% endblock %}
+
+
+ {% resource 'ckanext-textpreview/main' %}
+{% endblock %}
diff --git a/doc/configuration.rst b/doc/configuration.rst
index 4fdf1e29f48..6d6c7d29191 100644
--- a/doc/configuration.rst
+++ b/doc/configuration.rst
@@ -32,7 +32,7 @@ settings, for reference.
[app:main]
# This setting will work.
- ckan.plugins = stats json_preview recline_preview
+ ckan.plugins = stats text_preview recline_preview
If the same option is set more than once in your config file, the last
setting given in the file will override the others.
@@ -513,6 +513,8 @@ Example::
ckan.plugins = disqus datapreview googleanalytics follower
+Default value: ``stats text_preview recline_preview``
+
Specify which CKAN plugins are to be enabled.
.. warning:: If you specify a plugin but have not installed the code, CKAN will not start.
@@ -734,9 +736,9 @@ ckan.preview.direct
Example::
- ckan.preview.direct = png jpg gif
+ ckan.preview.direct = png jpg jpeg gif
-Default value: ``png jpg gif``
+Default value: ``png jpg jpeg gif``
Defines the resource formats which should be embedded directly in an ``img`` tag
when previewing them.
@@ -753,7 +755,7 @@ Example::
Default value: ``html htm rdf+xml owl+xml xml n3 n-triples turtle plain atom rss txt``
Defines the resource formats which should be loaded directly in an ``iframe``
-tag when previewing them.
+tag when previewing them if no :doc:`data-viewer` can preview it.
.. _ckan.dumps_url:
diff --git a/doc/data-viewer.rst b/doc/data-viewer.rst
index e76416f421a..2a446de4724 100644
--- a/doc/data-viewer.rst
+++ b/doc/data-viewer.rst
@@ -47,12 +47,14 @@ the resource read page:
* ``png``
* ``jpg``
+* ``jpeg``
* ``gif``
The types of resources that are embedded directly can be specified in the
CKAN config file. See :ref:`ckan.preview.direct` for more information.
-The following types of resources will be loaded in an iframe:
+The following types of resources will be loaded in an iframe if there is no
+extension that can preview these types:
* ``plain``
* ``txt``
@@ -70,6 +72,10 @@ The following types of resources will be loaded in an iframe:
The types of resources that are loaded in an iframe can be specified in the
CKAN config file. See :ref:`ckan.preview.loadable` for more information.
+Note that these documents will be directly linked by the browser, so the
+way in which they are shown may vary. If you want to ensure for instance that
+XML based documents are correctly previewed, have a look at `Viewing highlighted XML, JSON and plain text data`_.
+
Viewing structured data: the Data Explorer
------------------------------------------
@@ -106,25 +112,34 @@ Or:
reliable than viewing data that is in the DataStore.
-Viewing JSON data
------------------
+Viewing highlighted XML, JSON and plain text data
+-------------------------------------------------
-**Configuration required:** The ``json_preview`` extension must be added to
+**Configuration required:** The ``text_preview`` extension must be added to
``ckan.plugins`` in your CKAN configuration file. If you wish to view
-external JSON resources as well, the ``resource_proxy`` extension must also
+external files resources as well, the ``resource_proxy`` extension must also
be enabled.
These extensions are part of CKAN and so do not need to be installed
separately.
-**Resource formats:** ``json``, ``jsonp``.
+**Resource formats:**
+
+* ``json``, ``gjson``, ``geojson``
+ (can be configured by setting ``ckan.preview.json_formats``)
+* ``jsonp``
+ (can be configured by setting ``ckan.preview.jsonp_formats``)
+* ``xml``, ``rdf``, ``rdf+xml``, ``owl+xml``, ``atom``, ``rss``
+ (can be configured by setting ``ckan.preview.xml_formats``)
+* ``text/plain``, ``txt``, ``plain``
+ (can be configured by setting ``ckan.preview.text_formats``)
-The ``json_preview`` extension provides previews of any JSON data that has been
+The ``text_preview`` extension provides previews of many file types that have been
added to a CKAN instance
(and so are stored in the `Filestore `_).
-To view the data the resource format must be set to "json" or "jsonp"
-(case insensitive).
+To view the data the resource format must be set to one of the resource formats
+from above (case insensitive).
-To also view remote JSON resources, the ``resource_proxy`` extension must be
+To also view remote resources, the ``resource_proxy`` extension must be
enabled as well
(this is required in order to get around the
`same origin policy `_).
diff --git a/setup.py b/setup.py
index 6ae91c771bf..47da4ab1726 100644
--- a/setup.py
+++ b/setup.py
@@ -121,7 +121,7 @@
datastore=ckanext.datastore.plugin:DatastorePlugin
test_tag_vocab_plugin=ckanext.test_tag_vocab_plugin:MockVocabTagsPlugin
resource_proxy=ckanext.resourceproxy.plugin:ResourceProxy
- json_preview=ckanext.jsonpreview.plugin:JsonPreview
+ text_preview=ckanext.textpreview.plugin:TextPreview
pdf_preview=ckanext.pdfpreview.plugin:PdfPreview
recline_preview=ckanext.reclinepreview.plugin:ReclinePreview
example_itemplatehelpers=ckanext.example_itemplatehelpers.plugin:ExampleITemplateHelpersPlugin
@@ -131,7 +131,7 @@
domain_object_mods = ckan.model.modification:DomainObjectModificationExtension
[babel.extractors]
- ckan = ckan.lib.extract:extract_ckan
+ ckan = ckan.lib.extract:extract_ckan
""",
# setup.py test command needs a TestSuite so does not work with py.test
# test_suite = 'nose.collector',