oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1/* The clipboard's wire format.
2 *
3 * Tab-separated with the quoting every spreadsheet uses, and its own
4 * module because it is a CODEC where clipboard.js is a PROTOCOL: one
5 * decides what the characters mean, the other decides which events to
6 * take and what to write. Split out when clipboard.js reached the
7 * 300-line cap, along that seam rather than at whatever line the cap
8 * happened to fall on.
9 *
10 * The quoting is not decoration. Without it one cell of wrapped text
11 * turns into two rows on the way back in — the same silent corruption
12 * this whole area exists to remove, and a cell holding a tab or a
13 * newline is exactly what a person pastes out of a document.
14 */
15(function () {
16 'use strict';
17
18 window.SheetsTSV = {
19 /* encode reads a rectangle through the `at(r, c)` the caller
20 * supplies. The codec never touches the grid itself, which is what
21 * lets it be tested against a plain function. */
22 encode: function (box, at) {
23 var rows = [], r, c, row;
24 for (r = box.r1; r <= box.r2; r++) {
25 for (row = [], c = box.c1; c <= box.c2; c++) row.push(quote(at(r, c)));
26 rows.push(row.join('\t'));
27 }
28 return rows.join('\n');
29 },
30
31 /* decode reads a character at a time rather than splitting: a
32 * quoted field may contain the very characters a split would break
33 * on, which is the whole reason it is quoted. */
34 decode: function (text) {
35 var rows = [], row = [], field = '', quoted = false, i = 0, ch;
36 for (; i < text.length; i++) {
37 ch = text[i];
38 if (quoted) {
39 if (ch !== '"') { field += ch; continue; }
40 if (text[i + 1] === '"') { field += '"'; i++; continue; }
41 quoted = false;
42 continue;
43 }
44 if (ch === '"' && field === '') { quoted = true; continue; }
45 if (ch === '\t') { row.push(field); field = ''; continue; }
46 if (ch === '\r') continue;
47 if (ch === '\n') { row.push(field); rows.push(row); row = []; field = ''; continue; }
48 field += ch;
49 }
50 row.push(field);
51 rows.push(row);
52 /* A trailing newline is a line ending, not an empty last row —
53 * every editor writes one, and pasting it would clear a row. */
54 if (rows.length > 1 && rows[rows.length - 1].length === 1 &&
55 rows[rows.length - 1][0] === '') rows.pop();
56 return rows;
57 }
58 };
59
60 function quote(v) {
61 if (!/[\t\n\r"]/.test(v)) return v;
62 return '"' + v.replace(/"/g, '""') + '"';
63 }
64}());
65