Skip to content

Commit ba54017

Browse files
Make the plugin work more predictable and maintainable
1 parent bc6eebf commit ba54017

File tree

2 files changed

+51
-28
lines changed

2 files changed

+51
-28
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ The plugin supports *private spreadsheets* as well. However, to read data from a
2727
| Value | Description |
2828
|---------------|---------------------------------------------------------------------------------------------------------|
2929
| `sheet` | (*Optional*) A sheet title to read/write data from/to. If not provided, the first visible sheet will be used. <br /> **Note:** If there is no sheet with the specified name in the spreadsheet, it will be created while saving data. |
30-
| `range` | (*Optional*) A range with data in *A1 notation*. If not specified, supposed all the cells in the sheet. |
30+
| `range` | (*Optional*) A range with data in *A1 notation*. If not specified, the plugin will try to find the first not empty range of cells with data. |
3131
| `spreadsheet` | (*Optional*) A spreadsheet id. The value between the `/d/` and the `/edit` in the URL of a spreadsheet. By specifying this value, you can redefine the spreadsheet id the plugin got from the provided spreadsheet URL. In other words, you'll be able to work with another spreadsheet. |
3232

3333
**Note:** We recommend providing either *sheet title* or *range* to avoid extra network requests.
@@ -42,8 +42,6 @@ This is a string like `A1:B2` that refers to a group of cells in the sheet (the
4242
- `A5:A` refers to all the cells of the first column of the sheet, from row 5 onward.
4343
- `C2:2` refers to all the cells of the second row of the sheet, from column C onward.
4444

45-
If not specified, supposed all the cells in the sheet.
46-
4745
Named ranges are also supported.
4846

4947
## Customization

mavo-gsheets.js

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -164,39 +164,52 @@
164164
return null;
165165
}
166166

167-
if (this.dataInColumns) {
168-
// Transpose the array with data (https://stackoverflow.com/questions/17428587/transposing-a-2d-array-in-javascript)
169-
rawValues = rawValues[0].map((_, colIndex) => rawValues.map(row => row[colIndex]));
170-
}
167+
// Search for the beginning of data.
168+
let startRow = 0;
169+
let startColumn;
170+
for (const row of rawValues) {
171+
startColumn = row.findIndex(cell => cell?.effectiveValue);
171172

172-
// Range of indices of columns with data
173-
const start = rawValues[0].findIndex(el => el?.effectiveValue);
174-
if (start === -1) {
175-
// There is no data to work with
176-
return null;
173+
if (startColumn !== -1) {
174+
break;
175+
}
176+
177+
startRow += 1;
177178
}
178179

179-
const reversed = [...rawValues[0]].reverse();
180-
const end = reversed.length - reversed.findIndex(el => el?.effectiveValue) - 1;
180+
if (startRow >= rawValues.length || startColumn === -1) {
181+
// No data to work with
182+
return null
183+
}
181184

182-
const values = [];
183-
for (let rowIndex = 0; rowIndex < rawValues.length; rowIndex++) {
184-
const row = rawValues[rowIndex];
185-
if (!row) {
185+
// Search for the end of the first range of data.
186+
let endRow;
187+
for (let row = startRow; row < rawValues.length; row++) {
188+
if (!rawValues[row]?.[startColumn] || !rawValues[row]?.[startColumn]?.effectiveValue) {
189+
endRow = row - 1;
186190
break;
187191
}
192+
}
193+
endRow = endRow ?? rawValues.length - 1;
194+
195+
let endColumn = rawValues[startRow].findIndex((cell, index) => index > startColumn && !cell?.effectiveValue);
196+
endColumn = endColumn === -1 ? rawValues[startRow].length - 1 : endColumn - 1;
188197

189-
let emptyCellsCount = 0;
198+
// Save data offset inside raw values to be able to store data back in the same range as the source data.
199+
this.rowOffset = startRow;
200+
this.columnOffset = startColumn;
190201

202+
let values = [];
203+
for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {
204+
const row = rawValues[rowIndex];
191205
const ret = [];
192206

193-
for (let colIndex = start; colIndex <= end; colIndex++) {
194-
const cell = row[colIndex];
207+
for (let columnIndex = startColumn; columnIndex <= endColumn; columnIndex++) {
208+
const cell = row[columnIndex];
195209
let value;
196210

197211
if (!cell?.effectiveValue) {
198212
// We have an empty cell
199-
emptyCellsCount += 1;
200213
ret.push(undefined);
201214
continue;
202215
}
@@ -237,14 +250,14 @@
237250
ret.push(value);
238251
}
239252

240-
if (emptyCellsCount === end - start + 1) {
241-
// Skip rows of empty cells
242-
continue;
243-
}
244-
245253
values.push(ret);
246254
}
247255

256+
if (this.dataInColumns) {
257+
// Transpose the array with data (https://stackoverflow.com/questions/17428587/transposing-a-2d-array-in-javascript)
258+
values = values[0].map((_, columnIndex) => values.map(row => row[columnIndex]));
259+
}
260+
248261
// We need to store the loaded data so that we can perform diff later.
249262
// Why? Because Google Sheets has a built-in version history and we want to benefit from it.
250263
// And if every time we overwrite the full data range, it makes the version history useless.
@@ -383,6 +396,18 @@
383396
data = data.concat(records);
384397
}
385398

399+
// Add “empty” rows and columns to data so we could store them in the same range we got the source data from.
400+
const emptyRecord = this.columnOffset > 0 ? Array(this.columnOffset + data[0].length).fill(undefined) : []; // [undefined, ..., undefined]
401+
const emptyRecords = this.rowOffset > 0 ? Array(this.rowOffset).fill(emptyRecord) : []; // [ [undefined, ..., undefined], [undefined, ..., undefined], ..., [undefined, ..., undefined] ]
402+
403+
if (this.columnOffset > 0) {
404+
// Prepend every row with “empty” columns.
405+
data = data.map(row => [...Array(this.columnOffset).fill(undefined), ...row]); // [undefined, ..., undefined, data, data, ..., data]
406+
}
407+
408+
// Prepend data with “empty” rows.
409+
data = [...emptyRecords, ...data]; // [ [undefined, ..., undefined, undefined, undefined, ..., undefined], ..., [undefined, ..., undefined, undefined, undefined, ..., undefined], [undefined, ..., undefined, data, data, ..., data], ..., [undefined, ..., undefined, data, data, ..., data] ]
410+
386411
// Write the new data.
387412
const url = _.buildURL(this.apiURL, {
388413
"valueInputOption": "user_entered",
@@ -481,7 +506,7 @@
481506
};
482507

483508
// Saved successfully, update the fields.
484-
this.loadedData = res.updatedData.values;
509+
this.loadedData = res.updatedData?.values;
485510
this.recordCount = recordCount;
486511

487512
return res;

0 commit comments

Comments
 (0)