@@ -208,41 +208,14 @@ var GoogleSpreadsheet = function( ss_key, auth_id, options ){
208
208
209
209
var worksheets = forceArray ( response . sheets ) ; // not sure what this does -- seems to just initialize the array to []
210
210
worksheets . forEach ( function ( ws_data ) {
211
- ss_data . worksheets . push ( new SpreadsheetWorksheet ( self , ws_data ) ) ; //## TODO
211
+ ss_data . worksheets . push ( new SpreadsheetWorksheet ( self , ws_data ) ) ;
212
212
} ) ;
213
213
self . info = ss_data ;
214
214
self . worksheets = ss_data . worksheets ;
215
215
cb ( null , ss_data ) ;
216
216
217
217
}
218
- } ) ;
219
-
220
-
221
-
222
- //## OLD:
223
- /*
224
- self.makeFeedRequest( ["worksheets", ss_key], 'GET', null, function(err, data, xml) {
225
- if ( err ) return cb( err );
226
- if (data===true) {
227
- return cb(new Error('No response to getInfo call'))
228
- }
229
- var ss_data = {
230
- id: data.id,
231
- title: data.title,
232
- updated: data.updated,
233
- author: data.author,
234
- worksheets: []
235
- }
236
-
237
- var worksheets = forceArray(data.entry);
238
- worksheets.forEach( function( ws_data ) {
239
- ss_data.worksheets.push( new SpreadsheetWorksheet( self, ws_data ) );
240
- });
241
- self.info = ss_data;
242
- self.worksheets = ss_data.worksheets;
243
- cb( null, ss_data );
244
- });
245
- */
218
+ } ) ;
246
219
}
247
220
248
221
@@ -299,22 +272,25 @@ var GoogleSpreadsheet = function( ss_key, auth_id, options ){
299
272
}
300
273
*/
301
274
275
+ //## Complete
302
276
this . getRows = function ( worksheet_id , opts , cb ) {
303
- // the first row is used as titles/keys and is not included
277
+ // The first row is used as titles/keys and is not included (## is now included)
304
278
305
279
// opts is optional
306
280
if ( typeof ( opts ) == 'function' ) {
307
281
cb = opts ;
308
282
opts = { } ;
309
283
}
310
284
311
- //## NEW:
285
+ // Form request
312
286
var A1Range = '' + worksheet_id ; // e.g. "Sheet1!A1:B2"
313
287
var getReq = {
314
288
auth : jwt_client ,
315
289
spreadsheetId : ss_key ,
316
- range : A1Range
290
+ range : A1Range ,
317
291
} ;
292
+
293
+ // Request data from Google Sheets
318
294
sheets . spreadsheets . values . get ( getReq , function ( err , response ) {
319
295
if ( err ) {
320
296
console . log ( 'getRows: ERROR: ' + err ) ;
@@ -326,6 +302,7 @@ var GoogleSpreadsheet = function( ss_key, auth_id, options ){
326
302
var range = response . range ; // e.g. "range": "'Class Data'!A1:Z988",
327
303
var majorDimension = response . majorDimension ; // e.g. "majorDimension": "ROWS",
328
304
305
+ // Read rows
329
306
var rows = [ ] ;
330
307
var entries = forceArray ( response . values ) ;
331
308
@@ -337,59 +314,13 @@ var GoogleSpreadsheet = function( ss_key, auth_id, options ){
337
314
338
315
// Populate spreadsheet rows
339
316
for ( var rowNum = 0 ; rowNum < entries . length ; rowNum ++ ) {
340
- rows . push ( new SpreadsheetRow ( self , rowNum , entries [ rowNum ] , header ) ) ; //## TODO
317
+ rows . push ( new SpreadsheetRow ( jwt_client , ss_key , worksheet_id , rowNum , entries [ rowNum ] , header ) ) ; //## TODO
341
318
}
342
319
343
320
// Callback
344
321
cb ( null , rows ) ;
345
322
}
346
- } ) ;
347
-
348
-
349
- //## OLD:
350
- /*
351
- var query = {}
352
-
353
- if ( opts.offset ) query["start-index"] = opts.offset;
354
- else if ( opts.start ) query["start-index"] = opts.start;
355
-
356
- if ( opts.limit ) query["max-results"] = opts.limit;
357
- else if ( opts.num ) query["max-results"] = opts.num;
358
-
359
- if ( opts.orderby ) query["orderby"] = opts.orderby;
360
- if ( opts.reverse ) query["reverse"] = 'true';
361
- if ( opts.query ) query['sq'] = opts.query;
362
-
363
- self.makeFeedRequest( ["list", ss_key, worksheet_id], 'GET', query, function(err, data, xml) {
364
- if ( err ) return cb( err );
365
- if (data===true) {
366
- return cb(new Error('No response to getRows call'))
367
- }
368
-
369
- // gets the raw xml for each entry -- this is passed to the row object so we can do updates on it later
370
-
371
- var entries_xml = xml.match(/<entry[^>]*>([\s\S]*?)<\/entry>/g);
372
-
373
-
374
- // need to add the properties from the feed to the xml for the entries
375
- var feed_props = _.clone(data.$);
376
- delete feed_props['gd:etag'];
377
- var feed_props_str = _.reduce(feed_props, function(str, val, key){
378
- return str+key+'=\''+val+'\' ';
379
- }, '');
380
- entries_xml = _.map(entries_xml, function(xml){
381
- return xml.replace('<entry ', '<entry '+feed_props_str);
382
- });
383
-
384
- var rows = [];
385
- var entries = forceArray( data.entry );
386
- var i=0;
387
- entries.forEach( function( row_data ) {
388
- rows.push( new SpreadsheetRow( self, row_data, entries_xml[ i++ ] ) );
389
- });
390
- cb(null, rows);
391
- });
392
- */
323
+ } ) ;
393
324
}
394
325
395
326
/*
@@ -571,53 +502,69 @@ var SpreadsheetWorksheet = function( spreadsheet, data ){
571
502
572
503
// Storage class for a spreadsheet row
573
504
//## Note: 'xml' is unused
574
- var SpreadsheetRow = function ( spreadsheet , rowIdx , data , header ) {
505
+ var SpreadsheetRow = function ( auth , ss_key , worksheetId , rowIdx , data , header ) {
575
506
var self = this ;
576
- this . rowIdx = rowIdx ;
577
- this . values = data ;
578
- this . header = header ;
507
+ this . _auth = auth ;
508
+ this . _ss_key = ss_key ;
509
+ this . _worksheetId = worksheetId ;
510
+ this . _rowIdx = rowIdx ;
511
+ //this.values = data;
512
+ this . _header = header ;
579
513
580
514
// Create map
581
- this . map = { } ;
515
+ // this.map = {};
582
516
for ( var i = 0 ; i < header . length ; i ++ ) {
583
517
var sanitizedLabel = sanitizeHeaderStr ( header [ i ] ) ;
584
- this . map [ sanitizedLabel ] = this . values [ i ] ;
518
+ this [ sanitizedLabel ] = data [ i ] ;
585
519
}
586
520
587
-
588
- //self['_xml'] = xml; // Depricate
589
-
590
- /*
591
- //## I am not entirely sure what this does, but I think it's to make a dictionary out of the data using the row headers
592
- Object.keys(data).forEach(function(key) {
593
- var val = data[key];
594
- if(key.substring(0, 4) === "gsx:") {
595
- if(typeof val === 'object' && Object.keys(val).length === 0) {
596
- val = null;
597
- }
598
- if (key == "gsx:") {
599
- self[key.substring(0, 3)] = val;
600
- } else {
601
- self[key.substring(4)] = val;
602
- }
603
- } else {
604
- if (key == "id") {
605
- self[key] = val;
606
- } else if (val['_']) {
607
- self[key] = val['_'];
608
- } else if ( key == 'link' ){
609
- self['_links'] = [];
610
- val = forceArray( val );
611
- val.forEach( function( link ){
612
- self['_links'][ link['$']['rel'] ] = link['$']['href'];
613
- });
614
- }
615
- }
616
- }, this);
617
- */
618
521
619
- /*
620
- self.save = function( cb ){
522
+ // Save this row to Google Maps
523
+ self . save = function ( cb ) {
524
+
525
+ // Convert from map to flat values array
526
+ var values = [ ] ;
527
+ for ( var i = 0 ; i < this . _header . length ; i ++ ) {
528
+ var sanitizedLabel = sanitizeHeaderStr ( this . _header [ i ] ) ;
529
+ values . push ( this [ sanitizedLabel ] ) ;
530
+ }
531
+
532
+ // Create ValueRange GoogleSheets API v4 structure for this row
533
+ //var A1Range = '' + worksheet_id + '!' + XYtoA1(0, this.rowIdx) + ':' + XYtoA1(this.values.length-1, this.rowIdx); // e.g. "Sheet1!A1:B2"
534
+ var A1Range = '' + this . _worksheetId + '!' + ( this . _rowIdx + 1 ) + ':' + ( this . _rowIdx + 1 ) ; // e.g. "Sheet1!A1:B2"
535
+ var valueRange = {
536
+ range : A1Range ,
537
+ majorDimension : 'ROWS' ,
538
+ values : [ values ] ,
539
+ } ;
540
+
541
+ var request = {
542
+ auth : this . _auth ,
543
+ spreadsheetId : this . _ss_key ,
544
+ range : A1Range ,
545
+ valueInputOption : 'RAW' ,
546
+ resource : valueRange
547
+ }
548
+
549
+ //console.log("Save Request: \n" + JSON.stringify( request, null, 4 ) );
550
+
551
+ var sheets = google . sheets ( 'v4' ) ;
552
+ sheets . spreadsheets . values . update ( request , function ( err , response ) {
553
+ if ( err ) {
554
+ console . log ( 'SpeadsheetRow.save(): ERROR: ' + err ) ;
555
+ console . log ( 'request:\n\n ' + JSON . stringify ( request , null , 4 ) ) ;
556
+ return cb ( err ) ;
557
+ } else {
558
+ console . log ( 'SpeadsheetRow.save(): SUCCESS: ' ) ;
559
+ console . log ( JSON . stringify ( response , null , 4 ) ) ;
560
+
561
+ cb ( null , null ) ;
562
+ }
563
+ } ) ;
564
+ }
565
+
566
+ /*
567
+ //## OLD:
621
568
//API for edits is very strict with the XML it accepts
622
569
//So we just do a find replace on the original XML.
623
570
//It's dumb, but I couldnt get any JSON->XML conversion to work reliably
@@ -631,8 +578,8 @@ var SpreadsheetRow = function( spreadsheet, rowIdx, data, header){
631
578
}
632
579
});
633
580
spreadsheet.makeFeedRequest( self['_links']['edit'], 'PUT', data_xml, cb );
634
- }
635
- */
581
+ }*/
582
+
636
583
637
584
/*
638
585
self.del = function( cb ){
@@ -792,6 +739,20 @@ var sanitizeHeaderStr = function(strIn) {
792
739
return strOut ;
793
740
}
794
741
742
+
743
+ var XYtoA1 = function ( x , y ) {
744
+ var os = '' ;
745
+
746
+ // X
747
+ os += String . fromCharCode ( 65 + n ) ; // Up to 25/Z
748
+
749
+ // Y
750
+ os += ( y + 1 ) ;
751
+
752
+ return os ;
753
+ }
754
+
755
+
795
756
//## Remove?
796
757
var xmlSafeValue = function ( val ) {
797
758
if ( val == null ) return '' ;
0 commit comments