From 859776d5d2036447e1825c1072140065e0cba995 Mon Sep 17 00:00:00 2001 From: Jonathan Soma Date: Thu, 11 Dec 2014 11:43:32 -0500 Subject: [PATCH] default to prettyColumnNames: true --- README.md | 8 +- examples/backbone/backbone.html | 4 + examples/unfriendly_headers/index.html | 68 ++++++++++++ package.json | 2 +- src/tabletop.js | 140 +++++++++++++++++-------- 5 files changed, 176 insertions(+), 46 deletions(-) create mode 100644 examples/unfriendly_headers/index.html diff --git a/README.md b/README.md index 56529a3..4291d2f 100755 --- a/README.md +++ b/README.md @@ -120,7 +120,9 @@ You pass in either `key` as the actual spreadsheet key, or just the full publish `callbackContext` sets the `this` for your callback. It's the tabletop object by default. -`prettyColumnNames` can be true or false (default to false). It adds an object `pretty_columns` as a sibling to `column_names` which contains human-readable column names. +`prettyColumnNames` can be true or false (default to true). Since Google doesn't pass us exactly the same column names as in the header ('$ Processed' becomes 'processed'), it takes an extra request to correct them. If you don't want the extra request, you'll want to set it to `false` + +> See the **unfriendly_headers** example for more info. Only works for newer Google Sheets. ### Tabletop itself @@ -148,6 +150,10 @@ Tabletop.Model is pretty boring, let's be honest. `.column_names` gives you the names of the columns in that table +`.original_columns` gives you the names of the columns that Google sends on the first pass (numbers stripped, lowercase, etc) + +`.pretty_columns` gives you the mapping between the column headers in the spreadsheet and the and the `column_names`. Disabled by passing `prettyColumnNames: false` when initializing Tabletop. + `.all()` returns an array of the rows of the table, in the style of `[ { name: "Tom", age: 5}, { name: "Liz", age: 12 } ]` `.toArray()` returns the rows of the table with numbered indices instead of named ones [ [ "Tom", 5] , [ "Liz", 12 ] ] diff --git a/examples/backbone/backbone.html b/examples/backbone/backbone.html index cf52d3f..5e2904e 100755 --- a/examples/backbone/backbone.html +++ b/examples/backbone/backbone.html @@ -86,6 +86,10 @@

age <%= age %>

}); function showInfo(cats) { + var henry_view = new CatView({ model: cats.get('Henry') }); + + $("#content").append( henry_view.render().el ); + var bosco_view = new CatView({ model: cats.get('Bosco') }); $("#content").append( bosco_view.render().el ); diff --git a/examples/unfriendly_headers/index.html b/examples/unfriendly_headers/index.html new file mode 100644 index 0000000..9d10ec5 --- /dev/null +++ b/examples/unfriendly_headers/index.html @@ -0,0 +1,68 @@ + + + + +

Human-Readable Column Names (default)

+ +
+ +

Google-Readable Column Names (legacy)

+ +
+ + + + + + diff --git a/package.json b/package.json index 705595b..568e252 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tabletop", - "version": "1.3.5", + "version": "1.4.0", "description": "**Tabletop.js** takes a Google Spreadsheet and makes it easily accessible through JavaScript. With zero dependencies!", "main": "src/tabletop.js", "directories": { diff --git a/src/tabletop.js b/src/tabletop.js index 6e28497..f5faa18 100755 --- a/src/tabletop.js +++ b/src/tabletop.js @@ -69,7 +69,7 @@ this.singleton = !!options.singleton; this.simple_url = !!options.simple_url; this.callbackContext = options.callbackContext; - this.prettyColumnNames = !!options.prettyColumnNames; + this.prettyColumnNames = typeof(options.prettyColumnNames) == 'undefined' ? true : options.prettyColumnNames if(typeof(options.proxy) !== 'undefined') { // Remove trailing slash, it will break the app @@ -354,57 +354,33 @@ } }, - /* - Parse a single list-based worksheet, turning it into a Tabletop Model - - Used as a callback for the list-based JSON - */ - loadSheet: function(data) { - var model = new Tabletop.Model( { data: data, - parseNumbers: this.parseNumbers, - postProcess: this.postProcess, - tabletop: this } ); + sheetReady: function(model) { this.models[ model.name ] = model; if(ttIndexOf(this.model_names, model.name) === -1) { this.model_names.push(model.name); } - if (this.prettyColumnNames) { - var cellurl = data.feed.link[3].href.replace('/feeds/list/', '/feeds/cells/').replace('https://spreadsheets.google.com', ''); - this.requestData(cellurl, this.loadPrettyColumnNames); - } else { - this.sheetsToLoad--; - if(this.sheetsToLoad === 0) - this.doCallback(); - } - }, - - /* - * Store column names as an object - * with keys of Google-formatted "columnName" - * and values of uman-readable "Column name" - */ - loadPrettyColumnNames: function(data) { - var pretty_columns = {}; - - var column_names = this.models[data.feed.title.$t].column_names; - - var i = 0; - var l = column_names.length; - - for (; i < l; i++) { - if (typeof data.feed.entry[i].content.$t !== 'undefined') { - pretty_columns[column_names[i]] = data.feed.entry[i].content.$t; - } else { - pretty_columns[column_names[i]] = column_names[i]; - } - } - - this.models[data.feed.title.$t].pretty_columns = pretty_columns; this.sheetsToLoad--; if(this.sheetsToLoad === 0) this.doCallback(); }, + + /* + Parse a single list-based worksheet, turning it into a Tabletop Model + + Used as a callback for the list-based JSON + */ + loadSheet: function(data) { + var that = this; + var model = new Tabletop.Model( { data: data, + parseNumbers: this.parseNumbers, + postProcess: this.postProcess, + tabletop: this, + prettyColumnNames: this.prettyColumnNames, + onReady: function() { + that.sheetReady(this); + } } ); + }, /* Execute the callback upon loading! Rely on this.data() because you might @@ -437,7 +413,9 @@ var i, j, ilen, jlen; this.column_names = []; this.name = options.data.feed.title.$t; + this.tabletop = options.tabletop; this.elements = []; + this.onReady = options.onReady; this.raw = options.data; // A copy of the sheet's raw data, for accessing minutiae if(typeof(options.data.feed.entry) === 'undefined') { @@ -451,6 +429,8 @@ this.column_names.push( key.replace("gsx$","") ); } + this.original_columns = this.column_names; + for(i = 0, ilen = options.data.feed.entry.length ; i < ilen; i++) { var source = options.data.feed.entry[i]; var element = {}; @@ -471,7 +451,11 @@ options.postProcess(element); this.elements.push(element); } - + + if(options.prettyColumnNames) + this.fetchPrettyColumns(); + else + this.onReady.call(this); }; Tabletop.Model.prototype = { @@ -481,6 +465,74 @@ all: function() { return this.elements; }, + + fetchPrettyColumns: function() { + if(!this.raw.feed.link[3]) + return this.ready(); + var cellurl = this.raw.feed.link[3].href.replace('/feeds/list/', '/feeds/cells/').replace('https://spreadsheets.google.com', ''); + var that = this; + this.tabletop.requestData(cellurl, function(data) { + that.loadPrettyColumns(data) + }); + }, + + ready: function() { + this.onReady.call(this); + }, + + /* + * Store column names as an object + * with keys of Google-formatted "columnName" + * and values of human-readable "Column name" + */ + loadPrettyColumns: function(data) { + var pretty_columns = {}; + + var column_names = this.column_names; + + var i = 0; + var l = column_names.length; + + for (; i < l; i++) { + if (typeof data.feed.entry[i].content.$t !== 'undefined') { + pretty_columns[column_names[i]] = data.feed.entry[i].content.$t; + } else { + pretty_columns[column_names[i]] = column_names[i]; + } + } + + this.pretty_columns = pretty_columns; + + this.prettifyElements(); + this.ready(); + }, + + /* + * Go through each row, substitutiting + * Google-formatted "columnName" + * with human-readable "Column name" + */ + prettifyElements: function() { + var pretty_elements = [], + ordered_pretty_names = [], + i, j, ilen, jlen; + + var ordered_pretty_names; + for(j = 0, jlen = this.column_names.length; j < jlen ; j++) { + ordered_pretty_names.push(this.pretty_columns[this.column_names[j]]); + } + + for(i = 0, ilen = this.elements.length; i < ilen; i++) { + var new_element = {}; + for(j = 0, jlen = this.column_names.length; j < jlen ; j++) { + var new_column_name = this.pretty_columns[this.column_names[j]]; + new_element[new_column_name] = this.elements[i][this.column_names[j]]; + } + pretty_elements.push(new_element); + } + this.elements = pretty_elements; + this.column_names = ordered_pretty_names; + }, /* Return the elements as an array of arrays, instead of an array of objects