From a67df63fae0d158ff8ae03061ea19e30cb65f0b3 Mon Sep 17 00:00:00 2001 From: Dominik Moritz Date: Mon, 24 Sep 2012 20:29:59 +0100 Subject: [PATCH] rewrote recline to use the new module style --- ckan/public/base/datapreview/recline.js | 499 +++++++----------------- ckan/templates/dataviewer/recline.html | 4 +- 2 files changed, 149 insertions(+), 354 deletions(-) diff --git a/ckan/public/base/datapreview/recline.js b/ckan/public/base/datapreview/recline.js index 3b3f2fe0bd2..6894caff45b 100644 --- a/ckan/public/base/datapreview/recline.js +++ b/ckan/public/base/datapreview/recline.js @@ -1,125 +1,115 @@ -var CKAN = CKAN || {}; - -CKAN.View = CKAN.View || {}; -CKAN.Model = CKAN.Model || {}; -CKAN.Utils = CKAN.Utils || {}; -CKAN.Strings = CKAN.Strings || {}; - -/* TODO: set up properly */ -CKAN.Strings.errorLoadingPreview = "Could not load preview"; -CKAN.Strings.errorDataProxy = "DataProxy returned an error"; -CKAN.Strings.errorDataStore = "DataStore returned an error"; -CKAN.Strings.previewNotAvailableForDataType = "Preview not available for data type: "; - -(function ($) { - $(document).ready(function () { - CKAN.DataPreview.loadPreviewDialog(preload_resource); - }); -}(jQuery)); - -/* ==================== */ -/* == Data Previewer == */ -/* ==================== */ -CKAN.DataPreview = function ($, my) { - my.jsonpdataproxyUrl = 'http://jsonpdataproxy.appspot.com/'; - my.dialogId = 'ckanext-datapreview'; - my.$dialog = $('#' + my.dialogId); - - // **Public: Loads a data previewer for an embedded page** - // - // Uses the provided reclineState to restore the Dataset. Creates a single - // view for the Dataset (the one defined by reclineState.currentView). And - // then passes the constructed Dataset, the constructed View, and the - // reclineState into the DataExplorer constructor. - my.loadEmbeddedPreview = function(resourceData, reclineState) { - my.$dialog.html('

Loading ...

'); - - // Restore the Dataset from the given reclineState. - var dataset = recline.Model.Dataset.restore(reclineState); - - // Only create the view defined in reclineState.currentView. - // TODO: tidy this up. - var views = null; - if (reclineState.currentView === 'grid') { - views = [ { - id: 'grid', - label: 'Grid', - view: new recline.View.SlickGrid({ - model: dataset, - state: reclineState['view-grid'] - }) - }]; - } else if (reclineState.currentView === 'graph') { - views = [ { - id: 'graph', - label: 'Graph', - view: new recline.View.Graph({ - model: dataset, - state: reclineState['view-graph'] - }) - }]; - } else if (reclineState.currentView === 'map') { - views = [ { - id: 'map', - label: 'Map', - view: new recline.View.Map({ - model: dataset, - state: reclineState['view-map'] - }) - }]; - } - - // Finally, construct the DataExplorer. Again, passing in the reclineState. - var dataExplorer = new recline.View.MultiView({ - el: my.$dialog, - model: dataset, - state: reclineState, - views: views - }); - - }; - - // **Public: Creates a link to the embeddable page. - // - // For a given DataExplorer state, this function constructs and returns the - // url to the embeddable view of the current dataexplorer state. - my.makeEmbedLink = function(explorerState) { - var state = explorerState.toJSON(); - state.state_version = 1; - - var queryString = '?'; - var items = []; - $.each(state, function(key, value) { - if (typeof(value) === 'object') { - value = JSON.stringify(value); +// recline preview module +ckan.module('reclinepreview', function (jQuery, _) { + return { + options: { + i18n: { + errorLoadingPreview: "Could not load preview", + errorDataProxy: "DataProxy returned an error", + errorDataStore: "DataStore returned an error", + previewNotAvailableForDataType: "Preview not available for data type: " + } + }, + initialize: function() { + this.loadPreviewDialog(preload_resource); + }, + // **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) { + var self = this; + + function showError(msg){ + msg = msg || _('error loading preview'); + return $('#ckanext-datapreview') + .append('
') + .addClass('alert alert-error fade in') + .html(msg); } - items.push(key + '=' + escape(value)); - }); - queryString += items.join('&'); - return embedPath + queryString; - }; - // **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. - my.loadPreviewDialog = function(resourceData) { - my.$dialog.html('

Loading ...

'); + // 3 situations + // a) something was posted to the datastore - need to check for this + // b) csv or xls (but not datastore) + // c) can be treated as plain text + resourceData.formatNormalized = this.normalizeFormat(resourceData.format); + + resourceData.url = this.normalizeUrl(resourceData.url); + if (resourceData.formatNormalized === '') { + var tmp = resourceData.url.split('/'); + tmp = tmp[tmp.length - 1]; + tmp = tmp.split('?'); // query strings + tmp = tmp[0]; + var ext = tmp.split('.'); + if (ext.length > 1) { + resourceData.formatNormalized = ext[ext.length-1]; + } + } - function showError(msg){ - msg = msg || CKAN.Strings.errorLoadingPreview; - return $('#ckanext-datapreview') - .append('
') - .addClass('alert alert-error fade in') - .html(msg); - } + // Set recline CKAN backend API endpoint to right location (so it can locate + // CKAN DataStore) + recline.Backend.Ckan.API_ENDPOINT = $('body').data('site-root') + 'api'; + + if (resourceData.datastore_active) { + resourceData.backend = 'ckan'; + var dataset = new recline.Model.Dataset(resourceData); + var 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); + }); - function initializeDataExplorer(dataset) { + } 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'; + var dataset = new recline.Model.Dataset(resourceData); + var errorMsg = this.options.i18n.errorLoadingPreview + ': ' +this.options.i18n.errorDataProxy; + dataset.fetch() + .done(function(dataset){ + + dataset.bind('query:fail', function(error) { + $('.data-view-container', self.el).hide(); + $('.header', self.el).hide(); + }); + + self.initializeDataExplorer(dataset); + $('.recline-query-editor .text-query').hide(); + }) + .fail(function(error){ + if (error.message) errorMsg += ' (' + error.message + ')'; + showError(errorMsg); + }); + } else if (resourceData.formatNormalized in { + 'rdf+xml': '', + 'owl+xml': '', + 'xml': '', + 'n3': '', + 'n-triples': '', + 'turtle': '', + 'plain': '', + 'atom': '', + 'tsv': '', + 'rss': '', + 'txt': '' + }) { + // HACK: treat as plain text / csv + // pass url to jsonpdataproxy so we can load remote data (and tell dataproxy to treat as csv!) + var _url = this.jsonpdataproxyUrl + '?type=csv&url=' + resourceData.url; + this.getResourceDataDirect(_url, function(data) { + this.showPlainTextData(data); + }); + } + }, + initializeDataExplorer: function(dataset) { var views = [ { id: 'grid', @@ -145,7 +135,7 @@ CKAN.DataPreview = function ($, my) { ]; var dataExplorer = new recline.View.MultiView({ - el: my.$dialog, + el: this.el, model: dataset, views: views, config: { @@ -156,242 +146,45 @@ CKAN.DataPreview = function ($, my) { // Hide the fields control by default // (This should be done in recline!) $('.menu-right a[data-action="fields"]').click(); - - // ----------------------------- - // Setup the Embed modal dialog. - // ----------------------------- - - // embedLink holds the url to the embeddable view of the current DataExplorer state. - var embedLink = $('.embedLink'); - - // embedIframeText contains the '', - { - link: link.replace(/"/g, '"'), - width: width, - height: height - })); - embedLink.attr('href', link); - } - - // Bind changes to the DataExplorer, or the two width and height inputs - // to re-calculate the url. - dataExplorer.state.bind('change', updateLink); - for (var i=0; i 1) { - resourceData.formatNormalized = ext[ext.length-1]; + }, + showError: function (error) { + var _html = _.template( + '
<%= title %>
<%= message %>
', + error + ); + this.el.html(_html); + }, + 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); + } else { + return url; } - } - - // Set recline CKAN backend API endpoint to right location (so it can locate - // CKAN DataStore) - recline.Backend.Ckan.API_ENDPOINT = $('body').data('site-root') + 'api'; - - if (resourceData.datastore_active) { - resourceData.backend = 'ckan'; - var dataset = new recline.Model.Dataset(resourceData); - var errorMsg = CKAN.Strings.errorLoadingPreview + ': ' + CKAN.Strings.errorDataStore; - dataset.fetch() - .done(function(dataset){ - initializeDataExplorer(dataset); - }) - .fail(function(error){ - if (error.message) errorMsg += ' (' + error.message + ')'; - showError(errorMsg); - }); - - } - 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'; - var dataset = new recline.Model.Dataset(resourceData); - var errorMsg = CKAN.Strings.errorLoadingPreview + ': ' +CKAN.Strings.errorDataProxy; - dataset.fetch() - .done(function(dataset){ - - dataset.bind('query:fail', function(error) { - $('#ckanext-datapreview .data-view-container').hide(); - $('#ckanext-datapreview .header').hide(); - $('.preview-header .btn').hide(); - }); - - initializeDataExplorer(dataset); - $('.recline-query-editor .text-query').hide(); - }) - .fail(function(error){ - if (error.message) errorMsg += ' (' + error.message + ')'; - showError(errorMsg); - }); - } - else if (resourceData.formatNormalized in { - 'rdf+xml': '', - 'owl+xml': '', - 'xml': '', - 'n3': '', - 'n-triples': '', - 'turtle': '', - 'plain': '', - 'atom': '', - 'tsv': '', - 'rss': '', - 'txt': '' - }) { - // HACK: treat as plain text / csv - // pass url to jsonpdataproxy so we can load remote data (and tell dataproxy to treat as csv!) - var _url = my.jsonpdataproxyUrl + '?type=csv&url=' + resourceData.url; - my.getResourceDataDirect(_url, function(data) { - my.showPlainTextData(data); - }); - } - }; - - // Public: Requests the formatted resource data from the webstore and - // passes the data into the callback provided. - // - // preview - A preview object containing resource metadata. - // callback - A Function to call with the data when loaded. - // - // Returns nothing. - my.getResourceDataDirect = function(url, callback) { - // $.ajax() does not call the "error" callback for JSONP requests so we - // set a timeout to provide the callback with an error after x seconds. - var timeout = 5000; - var timer = setTimeout(function error() { - callback({ - error: { - title: 'Request Error', - message: 'Dataproxy server did not respond after ' + (timeout / 1000) + ' seconds' + }, + // **Public: Creates a link to the embeddable page. + // + // For a given DataExplorer state, this function constructs and returns the + // url to the embeddable view of the current dataexplorer state. + makeEmbedLink: function(explorerState) { + var state = explorerState.toJSON(); + state.state_version = 1; + + var queryString = '?'; + var items = []; + $.each(state, function(key, value) { + if (typeof(value) === 'object') { + value = JSON.stringify(value); } + items.push(key + '=' + escape(value)); }); - }, timeout); - - // have to set jsonp because webstore requires _callback but that breaks jsonpdataproxy - var jsonp = '_callback'; - if (url.indexOf('jsonpdataproxy') != -1) { - jsonp = 'callback'; - } - - // We need to provide the `cache: true` parameter to prevent jQuery appending - // a cache busting `={timestamp}` parameter to the query as the webstore - // currently cannot handle custom parameters. - $.ajax({ - url: url, - cache: true, - dataType: 'jsonp', - jsonp: jsonp, - success: function(data) { - clearTimeout(timer); - callback(data); - } - }); - }; - - // Public: Displays a String of data in a fullscreen dialog. - // - // data - An object of parsed CSV data returned by the webstore. - // - // Returns nothing. - my.showPlainTextData = function(data) { - if(data.error) { - my.showError(data.error); - } else { - var content = $('
');
-      for (var i=0; i<%= title %>
<%= message %>', - error - ); - my.$dialog.html(_html); - }; - - my.normalizeFormat = function(format) { - var out = format.toLowerCase(); - out = out.split('/'); - out = out[out.length-1]; - return out; - }; - - my.normalizeUrl = function(url) { - if (url.indexOf('https') === 0) { - return 'http' + url.slice(5); - } else { - return url; - } - }; - - // Public: Escapes HTML entities to prevent broken layout and XSS attacks - // when inserting user generated or external content. - // - // string - A String of HTML. - // - // Returns a String with HTML special characters converted to entities. - my.escapeHTML = function (string) { - return string.replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(/\//g,'/'); - }; - - - // Export the CKANEXT object onto the window. - $.extend(true, window, {CKANEXT: {}}); - CKANEXT.DATAPREVIEW = my; - return my; -}(jQuery, CKAN.DataPreview || {}); - +}); \ No newline at end of file diff --git a/ckan/templates/dataviewer/recline.html b/ckan/templates/dataviewer/recline.html index 0de13f52962..0afb6270075 100644 --- a/ckan/templates/dataviewer/recline.html +++ b/ckan/templates/dataviewer/recline.html @@ -1,7 +1,9 @@ {% extends "dataviewer/base.html" %} {% block page %} -
+
+

Loading ...

+
{% endblock %} {% block scripts %}