diff --git a/README.md b/README.md index a7fc7367..f4f582b0 100755 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ See CONTRIBUTING.md. Possible breaking changes +* Many backends moved to their own repositories #314 * Updated Leaflet to latest version 0.4.4 #220 * Added marker clustering in map view to handle a large number of markers * Dataset.restore method removed (not used internally except from Multiview.restore) diff --git a/_includes/recline-deps.html b/_includes/recline-deps.html index dbb4a23e..6055809a 100644 --- a/_includes/recline-deps.html +++ b/_includes/recline-deps.html @@ -53,7 +53,7 @@ - + diff --git a/dist/recline.js b/dist/recline.js index a163a421..41168e0c 100644 --- a/dist/recline.js +++ b/dist/recline.js @@ -383,174 +383,6 @@ this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {}; }(this.recline.Backend.DataProxy)); this.recline = this.recline || {}; this.recline.Backend = this.recline.Backend || {}; -this.recline.Backend.GDocs = this.recline.Backend.GDocs || {}; - -(function(my) { - "use strict"; - my.__type__ = 'gdocs'; - - // use either jQuery or Underscore Deferred depending on what is available - var Deferred = (typeof jQuery !== "undefined" && jQuery.Deferred) || _.Deferred; - - // ## Google spreadsheet backend - // - // Fetch data from a Google Docs spreadsheet. - // - // Dataset must have a url attribute pointing to the Gdocs or its JSON feed e.g. - //
- // var dataset = new recline.Model.Dataset({
- // url: 'https://docs.google.com/spreadsheet/ccc?key=0Aon3JiuouxLUdGlQVDJnbjZRSU1tUUJWOUZXRG53VkE#gid=0'
- // },
- // 'gdocs'
- // );
- //
- // var dataset = new recline.Model.Dataset({
- // url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json'
- // },
- // 'gdocs'
- // );
- //
- //
- // @return object with two attributes
- //
- // * fields: array of Field objects
- // * records: array of objects for each row
- my.fetch = function(dataset) {
- var dfd = new Deferred();
- var urls = my.getGDocsAPIUrls(dataset.url);
-
- // TODO cover it with tests
- // get the spreadsheet title
- (function () {
- var titleDfd = new Deferred();
-
- jQuery.getJSON(urls.spreadsheet, function (d) {
- titleDfd.resolve({
- spreadsheetTitle: d.feed.title.$t
- });
- });
-
- return titleDfd.promise();
- }()).then(function (response) {
-
- // get the actual worksheet data
- jQuery.getJSON(urls.worksheet, function(d) {
- var result = my.parseData(d);
- var fields = _.map(result.fields, function(fieldId) {
- return {id: fieldId};
- });
-
- dfd.resolve({
- metadata: {
- title: response.spreadsheetTitle +" :: "+ result.worksheetTitle,
- spreadsheetTitle: response.spreadsheetTitle,
- worksheetTitle : result.worksheetTitle
- },
- records : result.records,
- fields : fields,
- useMemoryStore: true
- });
- });
- });
-
- return dfd.promise();
- };
-
- // ## parseData
- //
- // Parse data from Google Docs API into a reasonable form
- //
- // :options: (optional) optional argument dictionary:
- // columnsToUse: list of columns to use (specified by field names)
- // colTypes: dictionary (with column names as keys) specifying types (e.g. range, percent for use in conversion).
- // :return: tabular data object (hash with keys: field and data).
- //
- // Issues: seems google docs return columns in rows in random order and not even sure whether consistent across rows.
- my.parseData = function(gdocsSpreadsheet, options) {
- var options = options || {};
- var colTypes = options.colTypes || {};
- var results = {
- fields : [],
- records: []
- };
- var entries = gdocsSpreadsheet.feed.entry || [];
- var key;
- var colName;
- // percentage values (e.g. 23.3%)
- var rep = /^([\d\.\-]+)\%$/;
-
- for(key in entries[0]) {
- // it's barely possible it has inherited keys starting with 'gsx$'
- if(/^gsx/.test(key)) {
- colName = key.substr(4);
- results.fields.push(colName);
- }
- }
-
- // converts non numberical values that should be numerical (22.3%[string] -> 0.223[float])
- results.records = _.map(entries, function(entry) {
- var row = {};
-
- _.each(results.fields, function(col) {
- var _keyname = 'gsx$' + col;
- var value = entry[_keyname].$t;
- var num;
-
- // TODO cover this part of code with test
- // TODO use the regexp only once
- // if labelled as % and value contains %, convert
- if(colTypes[col] === 'percent' && rep.test(value)) {
- num = rep.exec(value)[1];
- value = parseFloat(num) / 100;
- }
-
- row[col] = value;
- });
-
- return row;
- });
-
- results.worksheetTitle = gdocsSpreadsheet.feed.title.$t;
- return results;
- };
-
- // Convenience function to get GDocs JSON API Url from standard URL
- my.getGDocsAPIUrls = function(url) {
- // https://docs.google.com/spreadsheet/ccc?key=XXXX#gid=YYY
- var regex = /.*spreadsheet\/ccc?.*key=([^#?&+]+)[^#]*(#gid=([\d]+).*)?/;
- var matches = url.match(regex);
- var key;
- var worksheet;
- var urls;
-
- if(!!matches) {
- key = matches[1];
- // the gid in url is 0-based and feed url is 1-based
- worksheet = parseInt(matches[3], 10) + 1;
- if (isNaN(worksheet)) {
- worksheet = 1;
- }
- urls = {
- worksheet : 'https://spreadsheets.google.com/feeds/list/'+ key +'/'+ worksheet +'/public/values?alt=json',
- spreadsheet: 'https://spreadsheets.google.com/feeds/worksheets/'+ key +'/public/basic?alt=json'
- };
- }
- else {
- // we assume that it's one of the feeds urls
- key = url.split('/')[5];
- // by default then, take first worksheet
- worksheet = 1;
- urls = {
- worksheet : 'https://spreadsheets.google.com/feeds/list/'+ key +'/'+ worksheet +'/public/values?alt=json',
- spreadsheet: 'https://spreadsheets.google.com/feeds/worksheets/'+ key +'/public/basic?alt=json'
- };
- }
-
- return urls;
- };
-}(this.recline.Backend.GDocs));
-this.recline = this.recline || {};
-this.recline.Backend = this.recline.Backend || {};
this.recline.Backend.Memory = this.recline.Backend.Memory || {};
(function(my) {
diff --git a/docs/tutorial-backends.markdown b/docs/tutorial-backends.markdown
index 032452ba..1b27fb0a 100644
--- a/docs/tutorial-backends.markdown
+++ b/docs/tutorial-backends.markdown
@@ -76,8 +76,8 @@ much more limited if you are just using a Backend. Specifically:
-
-
+
+
@@ -99,6 +99,8 @@ a bespoke chooser and a Kartograph (svg-only) map.
{% highlight javascript %}
+// include the Recline backend for Google Docs
+
{% include example-backends-gdocs.js %}
{% endhighlight %}
@@ -106,6 +108,8 @@ a bespoke chooser and a Kartograph (svg-only) map.
- // var dataset = new recline.Model.Dataset({
- // url: 'https://docs.google.com/spreadsheet/ccc?key=0Aon3JiuouxLUdGlQVDJnbjZRSU1tUUJWOUZXRG53VkE#gid=0'
- // },
- // 'gdocs'
- // );
- //
- // var dataset = new recline.Model.Dataset({
- // url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json'
- // },
- // 'gdocs'
- // );
- //
- //
- // @return object with two attributes
- //
- // * fields: array of Field objects
- // * records: array of objects for each row
- my.fetch = function(dataset) {
- var dfd = new Deferred();
- var urls = my.getGDocsAPIUrls(dataset.url);
-
- // TODO cover it with tests
- // get the spreadsheet title
- (function () {
- var titleDfd = new Deferred();
-
- jQuery.getJSON(urls.spreadsheet, function (d) {
- titleDfd.resolve({
- spreadsheetTitle: d.feed.title.$t
- });
- });
-
- return titleDfd.promise();
- }()).then(function (response) {
-
- // get the actual worksheet data
- jQuery.getJSON(urls.worksheet, function(d) {
- var result = my.parseData(d);
- var fields = _.map(result.fields, function(fieldId) {
- return {id: fieldId};
- });
-
- dfd.resolve({
- metadata: {
- title: response.spreadsheetTitle +" :: "+ result.worksheetTitle,
- spreadsheetTitle: response.spreadsheetTitle,
- worksheetTitle : result.worksheetTitle
- },
- records : result.records,
- fields : fields,
- useMemoryStore: true
- });
- });
- });
-
- return dfd.promise();
- };
-
- // ## parseData
- //
- // Parse data from Google Docs API into a reasonable form
- //
- // :options: (optional) optional argument dictionary:
- // columnsToUse: list of columns to use (specified by field names)
- // colTypes: dictionary (with column names as keys) specifying types (e.g. range, percent for use in conversion).
- // :return: tabular data object (hash with keys: field and data).
- //
- // Issues: seems google docs return columns in rows in random order and not even sure whether consistent across rows.
- my.parseData = function(gdocsSpreadsheet, options) {
- var options = options || {};
- var colTypes = options.colTypes || {};
- var results = {
- fields : [],
- records: []
- };
- var entries = gdocsSpreadsheet.feed.entry || [];
- var key;
- var colName;
- // percentage values (e.g. 23.3%)
- var rep = /^([\d\.\-]+)\%$/;
-
- for(key in entries[0]) {
- // it's barely possible it has inherited keys starting with 'gsx$'
- if(/^gsx/.test(key)) {
- colName = key.substr(4);
- results.fields.push(colName);
- }
- }
-
- // converts non numberical values that should be numerical (22.3%[string] -> 0.223[float])
- results.records = _.map(entries, function(entry) {
- var row = {};
-
- _.each(results.fields, function(col) {
- var _keyname = 'gsx$' + col;
- var value = entry[_keyname].$t;
- var num;
-
- // TODO cover this part of code with test
- // TODO use the regexp only once
- // if labelled as % and value contains %, convert
- if(colTypes[col] === 'percent' && rep.test(value)) {
- num = rep.exec(value)[1];
- value = parseFloat(num) / 100;
- }
-
- row[col] = value;
- });
-
- return row;
- });
-
- results.worksheetTitle = gdocsSpreadsheet.feed.title.$t;
- return results;
- };
-
- // Convenience function to get GDocs JSON API Url from standard URL
- my.getGDocsAPIUrls = function(url) {
- // https://docs.google.com/spreadsheet/ccc?key=XXXX#gid=YYY
- var regex = /.*spreadsheet\/ccc?.*key=([^#?&+]+)[^#]*(#gid=([\d]+).*)?/;
- var matches = url.match(regex);
- var key;
- var worksheet;
- var urls;
-
- if(!!matches) {
- key = matches[1];
- // the gid in url is 0-based and feed url is 1-based
- worksheet = parseInt(matches[3], 10) + 1;
- if (isNaN(worksheet)) {
- worksheet = 1;
- }
- urls = {
- worksheet : 'https://spreadsheets.google.com/feeds/list/'+ key +'/'+ worksheet +'/public/values?alt=json',
- spreadsheet: 'https://spreadsheets.google.com/feeds/worksheets/'+ key +'/public/basic?alt=json'
- };
- }
- else {
- // we assume that it's one of the feeds urls
- key = url.split('/')[5];
- // by default then, take first worksheet
- worksheet = 1;
- urls = {
- worksheet : 'https://spreadsheets.google.com/feeds/list/'+ key +'/'+ worksheet +'/public/values?alt=json',
- spreadsheet: 'https://spreadsheets.google.com/feeds/worksheets/'+ key +'/public/basic?alt=json'
- };
- }
-
- return urls;
- };
-}(this.recline.Backend.GDocs));
diff --git a/test/backend.gdocs.test.js b/test/backend.gdocs.test.js
deleted file mode 100644
index 0e860b9c..00000000
--- a/test/backend.gdocs.test.js
+++ /dev/null
@@ -1,320 +0,0 @@
-(function ($) {
-module("Backend GDocs");
-
-var sampleGDocsSpreadsheetMetadata = {
- feed: {
- category: [
- {
- term: "http://schemas.google.com/spreadsheets/2006#worksheet",
- scheme: "http://schemas.google.com/spreadsheets/2006"
- }
- ],
- updated: {
- $t: "2010-07-13T09:57:28.408Z"
- },
- xmlns: "http://www.w3.org/2005/Atom",
- title: {
- $t: "javascript-test",
- type: "text"
- },
- author: [
- {
- name: {
- $t: "okfn.rufus.pollock"
- },
- email: {
- $t: "okfn.rufus.pollock@gmail.com"
- }
- }
- ],
- openSearch$startIndex: {
- $t: "1"
- },
- xmlns$gs: "http://schemas.google.com/spreadsheets/2006",
- xmlns$openSearch: "http://a9.com/-/spec/opensearchrss/1.0/",
- entry: [
- {
- category: [
- {
- term: "http://schemas.google.com/spreadsheets/2006#worksheet",
- scheme: "http://schemas.google.com/spreadsheets/2006"
- }
- ],
- updated: {
- $t: "2010-07-13T09:57:28.408Z"
- },
- title: {
- $t: "Sheet1",
- type: "text"
- },
- content: {
- $t: "Sheet1",
- type: "text"
- },
- link: [
- {
- href: "https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/basic",
- type: "application/atom+xml",
- rel: "http://schemas.google.com/spreadsheets/2006#listfeed"
- },
- {
- href: "https://spreadsheets.google.com/feeds/cells/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/basic",
- type: "application/atom+xml",
- rel: "http://schemas.google.com/spreadsheets/2006#cellsfeed"
- },
- {
- href: "https://spreadsheets.google.com/tq?key=0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc&sheet=od6&pub=1",
- type: "application/atom+xml",
- rel: "http://schemas.google.com/visualization/2008#visualizationApi"
- },
- {
- href: "https://spreadsheets.google.com/feeds/worksheets/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/public/basic/od6",
- type: "application/atom+xml",
- rel: "self"
- }
- ],
- id: {
- $t: "https://spreadsheets.google.com/feeds/worksheets/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/public/basic/od6"
- }
- }
- ],
- link: [
- {
- href: "https://spreadsheets.google.com/pub?key=0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc",
- type: "text/html",
- rel: "alternate"
- },
- {
- href: "https://spreadsheets.google.com/feeds/worksheets/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/public/basic",
- type: "application/atom+xml",
- rel: "http://schemas.google.com/g/2005#feed"
- },
- {
- href: "https://spreadsheets.google.com/feeds/worksheets/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/public/basic?alt=json",
- type: "application/atom+xml",
- rel: "self"
- }
- ],
- openSearch$totalResults: {
- $t: "1"
- },
- id: {
- $t: "https://spreadsheets.google.com/feeds/worksheets/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/public/basic"
- }
- },
- version: "1.0",
- encoding: "UTF-8"
-}
-
-var sampleGDocsSpreadsheetData = {
- feed: {
- category: [
- {
- term: "http://schemas.google.com/spreadsheets/2006#list",
- scheme: "http://schemas.google.com/spreadsheets/2006"
- }
- ],
- updated: {
- $t: "2010-07-12T18:32:16.200Z"
- },
- xmlns: "http://www.w3.org/2005/Atom",
- xmlns$gsx: "http://schemas.google.com/spreadsheets/2006/extended",
- title: {
- $t: "Sheet1",
- type: "text"
- },
- author: [
- {
- name: {
- $t: "okfn.rufus.pollock"
- },
- email: {
- $t: "okfn.rufus.pollock@gmail.com"
- }
- }
- ],
- openSearch$startIndex: {
- $t: "1"
- },
- link: [
- {
- href: "http://spreadsheets.google.com/pub?key=0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc",
- type: "text/html",
- rel: "alternate"
- },
- {
- href: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values",
- type: "application/atom+xml",
- rel: "http://schemas.google.com/g/2005#feed"
- },
- {
- href: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json-in-script",
- type: "application/atom+xml",
- rel: "self"
- }
- ],
- xmlns$openSearch: "http://a9.com/-/spec/opensearchrss/1.0/",
- entry: [
- {
- category: [
- {
- term: "http://schemas.google.com/spreadsheets/2006#list",
- scheme: "http://schemas.google.com/spreadsheets/2006"
- }
- ],
- updated: {
- $t: "2010-07-12T18:32:16.200Z"
- },
- 'gsx$column-2': {
- $t: "1"
- },
- 'gsx$column-1': {
- $t: "A"
- },
- title: {
- $t: "A",
- type: "text"
- },
- content: {
- $t: "column-2: 1",
- type: "text"
- },
- link: [
- {
- href: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr",
- type: "application/atom+xml",
- rel: "self"
- }
- ],
- id: {
- $t: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cokwr"
- }
- },
- {
- category: [
- {
- term: "http://schemas.google.com/spreadsheets/2006#list",
- scheme: "http://schemas.google.com/spreadsheets/2006"
- }
- ],
- updated: {
- $t: "2010-07-12T18:32:16.200Z"
- },
- 'gsx$column-2': {
- $t: "2"
- },
- 'gsx$column-1': {
- $t: "b"
- },
- title: {
- $t: "b",
- type: "text"
- },
- content: {
- $t: "column-2: 2",
- type: "text"
- },
- link: [
- {
- href: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4",
- type: "application/atom+xml",
- rel: "self"
- }
- ],
- id: {
- $t: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cpzh4"
- }
- },
- {
- category: [
- {
- term: "http://schemas.google.com/spreadsheets/2006#list",
- scheme: "http://schemas.google.com/spreadsheets/2006"
- }
- ],
- updated: {
- $t: "2010-07-12T18:32:16.200Z"
- },
- 'gsx$column-2': {
- $t: "3"
- },
- 'gsx$column-1': {
- $t: "c"
- },
- title: {
- $t: "c",
- type: "text"
- },
- content: {
- $t: "column-2: 3",
- type: "text"
- },
- link: [
- {
- href: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cre1l",
- type: "application/atom+xml",
- rel: "self"
- }
- ],
- id: {
- $t: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values/cre1l"
- }
- }
- ],
- openSearch$totalResults: {
- $t: "3"
- },
- id: {
- $t: "http://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values"
- }
- },
- version: "1.0",
- encoding: "UTF-8"
-}
-
-test("GDocs Backend", function() {
- var dataset = new recline.Model.Dataset({
- url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json',
- backend: 'gdocs'
- });
-
- var stub = sinon.stub($, 'getJSON', function(options, cb) {
- var spreadsheetUrl = 'spreadsheets.google.com/feeds/worksheets/';
- var worksheetUrl = 'spreadsheets.google.com/feeds/list/';
-
- if (options.indexOf(spreadsheetUrl) !== -1) {
- cb(sampleGDocsSpreadsheetMetadata)
- }
- else if(options.indexOf(worksheetUrl) !== -1) {
- cb(sampleGDocsSpreadsheetData)
- }
- });
-
- dataset.fetch().then(function() {
- var docList = dataset.records;
- deepEqual(['column-2', 'column-1'], _.pluck(dataset.fields.toJSON(), 'id'));
- equal(3, docList.length);
- equal("A", docList.models[0].get('column-1'));
- equal('javascript-test :: Sheet1', dataset.get('title'));
- });
- $.getJSON.restore();
-});
-
-test("GDocs Backend.getUrl", function() {
- var key = 'Abc_dajkdkjdafkj';
- var gid = 0;
- var worksheet = 1;
- var url = 'https://docs.google.com/spreadsheet/ccc?key=' + key + '#gid=' + gid
- var out = recline.Backend.GDocs.getGDocsAPIUrls(url);
- var exp1 = 'https://spreadsheets.google.com/feeds/list/' + key + '/' + worksheet + '/public/values?alt=json'
- var exp2 = 'https://spreadsheets.google.com/feeds/worksheets/' + key + '/public/basic?alt=json'
- equal(exp1, out.worksheet);
- equal(exp2, out.spreadsheet);
-
- var url = 'https://docs.google.com/spreadsheet/ccc?key=' + key;
- var out = recline.Backend.GDocs.getGDocsAPIUrls(url);
- equal(out.worksheet, exp1);
-});
-
-})(this.jQuery);
-
diff --git a/test/index.html b/test/index.html
index 1c103cac..eb0cf8d8 100644
--- a/test/index.html
+++ b/test/index.html
@@ -40,13 +40,11 @@
-
-