Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 68a57a6112fb4fb6e92cd520538e742fee990a2f @tomvit committed Jul 25, 2011
Showing with 209 additions and 0 deletions.
  1. +19 −0 LICENSE.txt
  2. +1 −0 README.md
  3. +1 −0 index.js
  4. +177 −0 lib/feed-tables.js
  5. +11 −0 package.json
19 LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Tomas Vitvar <tomas@vitvar.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
1 README.md
@@ -0,0 +1 @@
+# Feed Tables
1 index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/feed-tables');
177 lib/feed-tables.js
@@ -0,0 +1,177 @@
+/**
+ * Feed-Tables - JavaScript parser for Google spreadsheet tables
+ * works for both client-side and node.js (server-side) JavaScript
+ *
+ * Feed-Tables provide parses for a Google spreadsheet that is in a form of a table,
+ * that is, it has a header in the first row with field names and
+ * values in remaining rows of the table.
+ *
+ * @author
+ * Tomas Vitvar, http://vitvar.com
+ *
+ * @version
+ * 0.1
+ *
+ * @Licesne
+ * MIT License
+ */
+
+/**
+ * Parser for list feeds. Since list feeds do not always contain
+ * all header fields, they must be provided explicitly when creating the parser.
+ * They are much smaller in size comparing to cells feeds though.
+ *
+ * @param data JSON data of the list feed
+ * @param headers array that contains names of header fields
+ */
+var ListFeed = function(data, headers) {
+
+ // check if this is what we are expecting
+ if (!data || !data.feed || !data.feed.category || data.feed.category.length === 0 ||
+ data.feed.category[0].scheme != "http://schemas.google.com/spreadsheets/2006" ||
+ data.feed.category[0].term != "http://schemas.google.com/spreadsheets/2006#list")
+ throw "The data must be in Google Spreadsheet List feed format!";
+
+ this.data = data.feed;
+ this.headers = headers;
+
+ for (var i = 0; i < this.headers.length; i++)
+ this.headers[i] = this.headers[i].toLowerCase();
+
+ // gets the cell value at row:col
+ this.getValueRC = function(row, col) {
+ if (row < this.length && col < this.headers.length) {
+ var r = this.data.entry[row];
+
+ if (col === 0)
+ return r.title.$t;
+ else {
+ for (var z = col; z < this.headers.length; z++) {
+ var s = ".*" + this.headers[col] + ":\s*(.*)" +
+ (z < this.headers.length - 1 ? (", " + this.headers[z+1] + ".*") : "");
+ var re = new RegExp(s);
+ if (re.test(r.content.$t))
+ return RegExp.$1;
+ }
+ return null;
+ }
+ } else
+ throw new Error('Index out of bounds (' + row + ',' + col +').');
+ };
+
+ // gets the value in the column with label header at specified row
+ this.getValue = function(header, row) {
+ var col = this.headers.indexOf(header.toLowerCase());
+ if (col == -1)
+ throw new Error('Header with value \'' + header + '\' does not exist!');
+ return this.getValueRC(row, col);
+ };
+
+ // gets the whole row as the object
+ this.getRow = function(row) {
+ if (row < this.length) {
+ var o = {};
+ for (var inx = 0; inx < this.headers.length; inx++)
+ o[this.headers[inx].toLowerCase()] =
+ this.getValue(this.headers[inx], row);
+ return o;
+ } else
+ throw new Error('Index out of bounds (' + row + ')');
+ };
+
+ // returns the length of the table
+ this.__defineGetter__('length', function() {
+ return Math.floor(this.data.entry.length);
+ });
+
+};
+
+/**
+ * Parser for cells feed.
+ *
+ * @param data JSON data of the cells feed
+ */
+var CellsFeed = function(data) {
+
+ // check if this is what we are expecting
+ if (!data || !data.feed || !data.feed.category || data.feed.category.length === 0 ||
+ data.feed.category[0].scheme != "http://schemas.google.com/spreadsheets/2006" ||
+ data.feed.category[0].term != "http://schemas.google.com/spreadsheets/2006#cell")
+ throw "The data must be in Google Spreadsheet List feed format!";
+
+ this.data = data.feed;
+ this.headers = [];
+
+ var col = 0;
+ var t = this.data.entry[col].title.$t;
+
+ // get cells from the table's header
+ while (t.substring(t.length - 1) == "1") {
+ this.headers.push(this.data.entry[col].content.$t);
+ col++;
+ t = this.data.entry[col].title.$t;
+ }
+
+ // gets the cells value at row:col
+ // all sheet cells are ordered and empty cells are not included;
+ // this uses the binary search to retrieve the value
+ this.getValueRC = function(row, col) {
+ var ft = this;
+
+ var bin_search = function(f, t) {
+ var p = (t-f)/2>>0;
+ var a = ft.data.entry[f+p].title.$t;
+ var c = a.charCodeAt(0) - 65;
+ var r = parseInt(a.substring(1));
+
+ var e;
+ if (r == row+2)
+ e = col == c ? 0 : col < c ? -1 : 1;
+ else
+ e = row+2 < r ? -1 : +1;
+
+ if (e === 0)
+ return ft.data.entry[f+p].content.$t;
+ else
+ if (e < 0 && p !== 0)
+ return bin_search(f, f+p);
+ else
+ if (e > 0 && p !== 0)
+ return bin_search(f+p+1, t);
+ else
+ return null;
+ };
+
+ return bin_search(this.headers.length, this.data.entry.length);
+ };
+
+ this.getValue = function(header, row) {
+ var col = this.headers.indexOf(header.toUpperCase());
+ if (col == -1)
+ throw new Error('Header with value \'' + header + '\' does not exist!');
+ return this.getValueRC(row, col);
+ };
+
+ this.getRow = function(row) {
+ if (row < this.length) {
+ var o = {};
+ for (var col = 0; col < this.headers.length; col++) {
+ var val = this.getValueRC(row, col);
+ o[this.headers[col].toLowerCase()] = val ? val : "";
+ }
+ return o;
+ } else
+ throw new Error('Index out of bounds (' + row + ')');
+ };
+
+ this.__defineGetter__('length', function() {
+ return parseInt(this.data.entry[this.data.entry.length - 1].title.$t.match("[0-9]+$")) - 1;
+ });
+
+};
+
+if (typeof window === 'undefined') {
+ // asume we are in node.js
+ exports.CellsFeed = CellsFeed;
+ exports.ListFeed = ListFeed;
+}
11 package.json
@@ -0,0 +1,11 @@
+{
+ "name":"feed-tables",
+ "author": "Tomas Vitvar <tomas@vitvar.com>",
+ "version": "0.1",
+ "description": "Simple API for accessing Google Spreadsheets data as tables for Node.js and client-side JavaScript",
+ "keywords": ["Goofle Spreadsheets", "server"],
+ "directories": {
+ "lib": "lib"
+ },
+ "main": "lib/feed-tables"
+}

0 comments on commit 68a57a6

Please sign in to comment.