Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

initial commit

  • Loading branch information...
commit 68a57a6112fb4fb6e92cd520538e742fee990a2f 0 parents
Tomas Vitvar authored
19 LICENSE.txt
... ... @@ -0,0 +1,19 @@
  1 +Copyright (c) 2011 Tomas Vitvar <tomas@vitvar.com>
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining a copy
  4 +of this software and associated documentation files (the "Software"), to deal
  5 +in the Software without restriction, including without limitation the rights
  6 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7 +copies of the Software, and to permit persons to whom the Software is
  8 +furnished to do so, subject to the following conditions:
  9 +
  10 +The above copyright notice and this permission notice shall be included in
  11 +all copies or substantial portions of the Software.
  12 +
  13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19 +THE SOFTWARE.
1  README.md
Source Rendered
... ... @@ -0,0 +1 @@
  1 +# Feed Tables
1  index.js
... ... @@ -0,0 +1 @@
  1 +module.exports = require('./lib/feed-tables');
177 lib/feed-tables.js
... ... @@ -0,0 +1,177 @@
  1 +/**
  2 + * Feed-Tables - JavaScript parser for Google spreadsheet tables
  3 + * works for both client-side and node.js (server-side) JavaScript
  4 + *
  5 + * Feed-Tables provide parses for a Google spreadsheet that is in a form of a table,
  6 + * that is, it has a header in the first row with field names and
  7 + * values in remaining rows of the table.
  8 + *
  9 + * @author
  10 + * Tomas Vitvar, http://vitvar.com
  11 + *
  12 + * @version
  13 + * 0.1
  14 + *
  15 + * @Licesne
  16 + * MIT License
  17 + */
  18 +
  19 +/**
  20 + * Parser for list feeds. Since list feeds do not always contain
  21 + * all header fields, they must be provided explicitly when creating the parser.
  22 + * They are much smaller in size comparing to cells feeds though.
  23 + *
  24 + * @param data JSON data of the list feed
  25 + * @param headers array that contains names of header fields
  26 + */
  27 +var ListFeed = function(data, headers) {
  28 +
  29 + // check if this is what we are expecting
  30 + if (!data || !data.feed || !data.feed.category || data.feed.category.length === 0 ||
  31 + data.feed.category[0].scheme != "http://schemas.google.com/spreadsheets/2006" ||
  32 + data.feed.category[0].term != "http://schemas.google.com/spreadsheets/2006#list")
  33 + throw "The data must be in Google Spreadsheet List feed format!";
  34 +
  35 + this.data = data.feed;
  36 + this.headers = headers;
  37 +
  38 + for (var i = 0; i < this.headers.length; i++)
  39 + this.headers[i] = this.headers[i].toLowerCase();
  40 +
  41 + // gets the cell value at row:col
  42 + this.getValueRC = function(row, col) {
  43 + if (row < this.length && col < this.headers.length) {
  44 + var r = this.data.entry[row];
  45 +
  46 + if (col === 0)
  47 + return r.title.$t;
  48 + else {
  49 + for (var z = col; z < this.headers.length; z++) {
  50 + var s = ".*" + this.headers[col] + ":\s*(.*)" +
  51 + (z < this.headers.length - 1 ? (", " + this.headers[z+1] + ".*") : "");
  52 + var re = new RegExp(s);
  53 + if (re.test(r.content.$t))
  54 + return RegExp.$1;
  55 + }
  56 + return null;
  57 + }
  58 + } else
  59 + throw new Error('Index out of bounds (' + row + ',' + col +').');
  60 + };
  61 +
  62 + // gets the value in the column with label header at specified row
  63 + this.getValue = function(header, row) {
  64 + var col = this.headers.indexOf(header.toLowerCase());
  65 + if (col == -1)
  66 + throw new Error('Header with value \'' + header + '\' does not exist!');
  67 + return this.getValueRC(row, col);
  68 + };
  69 +
  70 + // gets the whole row as the object
  71 + this.getRow = function(row) {
  72 + if (row < this.length) {
  73 + var o = {};
  74 + for (var inx = 0; inx < this.headers.length; inx++)
  75 + o[this.headers[inx].toLowerCase()] =
  76 + this.getValue(this.headers[inx], row);
  77 + return o;
  78 + } else
  79 + throw new Error('Index out of bounds (' + row + ')');
  80 + };
  81 +
  82 + // returns the length of the table
  83 + this.__defineGetter__('length', function() {
  84 + return Math.floor(this.data.entry.length);
  85 + });
  86 +
  87 +};
  88 +
  89 +/**
  90 + * Parser for cells feed.
  91 + *
  92 + * @param data JSON data of the cells feed
  93 + */
  94 +var CellsFeed = function(data) {
  95 +
  96 + // check if this is what we are expecting
  97 + if (!data || !data.feed || !data.feed.category || data.feed.category.length === 0 ||
  98 + data.feed.category[0].scheme != "http://schemas.google.com/spreadsheets/2006" ||
  99 + data.feed.category[0].term != "http://schemas.google.com/spreadsheets/2006#cell")
  100 + throw "The data must be in Google Spreadsheet List feed format!";
  101 +
  102 + this.data = data.feed;
  103 + this.headers = [];
  104 +
  105 + var col = 0;
  106 + var t = this.data.entry[col].title.$t;
  107 +
  108 + // get cells from the table's header
  109 + while (t.substring(t.length - 1) == "1") {
  110 + this.headers.push(this.data.entry[col].content.$t);
  111 + col++;
  112 + t = this.data.entry[col].title.$t;
  113 + }
  114 +
  115 + // gets the cells value at row:col
  116 + // all sheet cells are ordered and empty cells are not included;
  117 + // this uses the binary search to retrieve the value
  118 + this.getValueRC = function(row, col) {
  119 + var ft = this;
  120 +
  121 + var bin_search = function(f, t) {
  122 + var p = (t-f)/2>>0;
  123 + var a = ft.data.entry[f+p].title.$t;
  124 + var c = a.charCodeAt(0) - 65;
  125 + var r = parseInt(a.substring(1));
  126 +
  127 + var e;
  128 + if (r == row+2)
  129 + e = col == c ? 0 : col < c ? -1 : 1;
  130 + else
  131 + e = row+2 < r ? -1 : +1;
  132 +
  133 + if (e === 0)
  134 + return ft.data.entry[f+p].content.$t;
  135 + else
  136 + if (e < 0 && p !== 0)
  137 + return bin_search(f, f+p);
  138 + else
  139 + if (e > 0 && p !== 0)
  140 + return bin_search(f+p+1, t);
  141 + else
  142 + return null;
  143 + };
  144 +
  145 + return bin_search(this.headers.length, this.data.entry.length);
  146 + };
  147 +
  148 + this.getValue = function(header, row) {
  149 + var col = this.headers.indexOf(header.toUpperCase());
  150 + if (col == -1)
  151 + throw new Error('Header with value \'' + header + '\' does not exist!');
  152 + return this.getValueRC(row, col);
  153 + };
  154 +
  155 + this.getRow = function(row) {
  156 + if (row < this.length) {
  157 + var o = {};
  158 + for (var col = 0; col < this.headers.length; col++) {
  159 + var val = this.getValueRC(row, col);
  160 + o[this.headers[col].toLowerCase()] = val ? val : "";
  161 + }
  162 + return o;
  163 + } else
  164 + throw new Error('Index out of bounds (' + row + ')');
  165 + };
  166 +
  167 + this.__defineGetter__('length', function() {
  168 + return parseInt(this.data.entry[this.data.entry.length - 1].title.$t.match("[0-9]+$")) - 1;
  169 + });
  170 +
  171 +};
  172 +
  173 +if (typeof window === 'undefined') {
  174 + // asume we are in node.js
  175 + exports.CellsFeed = CellsFeed;
  176 + exports.ListFeed = ListFeed;
  177 +}
11 package.json
... ... @@ -0,0 +1,11 @@
  1 +{
  2 + "name":"feed-tables",
  3 + "author": "Tomas Vitvar <tomas@vitvar.com>",
  4 + "version": "0.1",
  5 + "description": "Simple API for accessing Google Spreadsheets data as tables for Node.js and client-side JavaScript",
  6 + "keywords": ["Goofle Spreadsheets", "server"],
  7 + "directories": {
  8 + "lib": "lib"
  9 + },
  10 + "main": "lib/feed-tables"
  11 +}

0 comments on commit 68a57a6

Please sign in to comment.
Something went wrong with that request. Please try again.