this.recline = this.recline || {}; this.recline.Backend = this.recline.Backend || {}; this.recline.Backend.GDocs = this.recline.Backend.GDocs || {}; (function($, my) { // ## Google spreadsheet backend // // Connect to Google Docs spreadsheet. // // Dataset must have a url attribute pointing to the Gdocs // spreadsheet's JSON feed e.g. // //
  // var dataset = new recline.Model.Dataset({
  //     url: 'https://spreadsheets.google.com/feeds/list/0Aon3JiuouxLUdDQwZE1JdV94cUd6NWtuZ0IyWTBjLWc/od6/public/values?alt=json'
  //   },
  //   'gdocs'
  // );
  // 
my.Backbone = function() { var self = this; this.__type__ = 'gdocs'; this.readonly = true; this.sync = function(method, model, options) { var self = this; if (method === "read") { var dfd = $.Deferred(); dfd.resolve(model); return dfd.promise(); } }; this.query = function(dataset, queryObj) { var dfd = $.Deferred(); if (dataset._dataCache) { dfd.resolve(dataset._dataCache); } else { loadData(dataset.get('url')).done(function(result) { dataset.fields.reset(result.fields); // cache data onto dataset (we have loaded whole gdoc it seems!) dataset._dataCache = self._formatResults(dataset, result.data); dfd.resolve(dataset._dataCache); }); } return dfd.promise(); }; this._formatResults = function(dataset, data) { var fields = _.pluck(dataset.fields.toJSON(), 'id'); // zip the fields with the data rows to produce js objs // TODO: factor this out as a common method with other backends var objs = _.map(data, function (d) { var obj = {}; _.each(_.zip(fields, d), function (x) { obj[x[0]] = x[1]; }); return obj; }); var out = { total: objs.length, hits: _.map(objs, function(row) { return { _source: row } }) } return out; }; }; // ## loadData // // loadData from a google docs URL // // @return object with two attributes // // * fields: array of objects // * data: array of arrays var loadData = function(url) { var dfd = $.Deferred(); var url = my.getSpreadsheetAPIUrl(url); var out = { fields: [], data: [] } $.getJSON(url, function(d) { result = my.parseData(d); result.fields = _.map(result.fields, function(fieldId) { return {id: fieldId}; }); dfd.resolve(result); }); 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) { var options = {}; if (arguments.length > 1) { options = arguments[1]; } var results = { 'fields': [], 'data': [] }; // default is no special info on type of columns var colTypes = {}; if (options.colTypes) { colTypes = options.colTypes; } if (gdocsSpreadsheet.feed.entry.length > 0) { for (var k in gdocsSpreadsheet.feed.entry[0]) { if (k.substr(0, 3) == 'gsx') { var col = k.substr(4); results.fields.push(col); } } } // converts non numberical values that should be numerical (22.3%[string] -> 0.223[float]) var rep = /^([\d\.\-]+)\%$/; $.each(gdocsSpreadsheet.feed.entry, function (i, entry) { var row = []; for (var k in results.fields) { var col = results.fields[k]; var _keyname = 'gsx$' + col; var value = entry[_keyname]['$t']; // if labelled as % and value contains %, convert if (colTypes[col] == 'percent') { if (rep.test(value)) { var value2 = rep.exec(value); var value3 = parseFloat(value2); value = value3 / 100; } } row.push(value); } results.data.push(row); }); return results; }; // Convenience function to get GDocs JSON API Url from standard URL my.getSpreadsheetAPIUrl = function(url) { if (url.indexOf('feeds/list') != -1) { return url; } else { // https://docs.google.com/spreadsheet/ccc?key=XXXX#gid=0 var regex = /.*spreadsheet\/ccc?.*key=([^#?&+]+).*/; var matches = url.match(regex); if (matches) { var key = matches[1]; var worksheet = 1; var out = 'https://spreadsheets.google.com/feeds/list/' + key + '/' + worksheet + '/public/values?alt=json'; return out; } else { alert('Failed to extract gdocs key from ' + url); } } }; }(jQuery, this.recline.Backend.GDocs));