| 1 | package sheets |
| 2 | |
| 3 | import ( |
| 4 | "strconv" |
| 5 | |
| 6 | "amadan.net/oficina/sheets/internal/sheets/calc" |
| 7 | "amadan.net/oficina/sheets/internal/sheets/store" |
| 8 | ) |
| 9 | |
| 10 | // tableview.go builds the table view's rows. |
| 11 | // |
| 12 | // Split out of handlers_table.go when that file reached the 300-line |
| 13 | // cap, and along a seam that was already there rather than at whatever |
| 14 | // line the cap happened to fall on: this file turns stored cells into |
| 15 | // what a page shows, and handlers_table.go decides which cells and what |
| 16 | // to do with a POST. The split is what the cap is for. |
| 17 | |
| 18 | // tableRows builds one page of rows. |
| 19 | // |
| 20 | // Shared with the anonymous link view, which passes editR/editC of -1 |
| 21 | // so no cell can ever match and none renders a form. Expressing |
| 22 | // read-only as a coordinate nothing equals — rather than as a flag the |
| 23 | // template is trusted to honour — means the read-only view cannot grow |
| 24 | // an edit form by somebody adding a branch to the template. |
| 25 | func (a *App) tableRows(h *store.Handle, first, editR, editC int) []tableRow { |
| 26 | order := make([]int, 0, tableRowsPerPage) |
| 27 | for i := 0; i < tableRowsPerPage; i++ { |
| 28 | order = append(order, first+i) |
| 29 | } |
| 30 | return a.tableRowsIn(h, order, editR, editC) |
| 31 | } |
| 32 | |
| 33 | // tableRowsIn builds rows in a given order. |
| 34 | // |
| 35 | // The order is a list of row POSITIONS, which is what lets a sorted or |
| 36 | // filtered view reuse every other part of this: each cell still carries |
| 37 | // its real coordinate, so an edit form posts the row it was always |
| 38 | // posting and nothing downstream needs to know a view is in effect. |
| 39 | func (a *App) tableRowsIn(h *store.Handle, order []int, editR, editC int) []tableRow { |
| 40 | idx := newPosIndex(h) |
| 41 | rows := make([]tableRow, 0, len(order)) |
| 42 | for _, rowIdx := range order { |
| 43 | row := tableRow{Number: rowIdx + 1} |
| 44 | for c := 0; c < tableCols; c++ { |
| 45 | cell := tableCell{ |
| 46 | R: rowIdx, C: c, |
| 47 | Ref: colLabel(c) + strconv.Itoa(rowIdx+1), |
| 48 | Editing: rowIdx == editR && c == editC, |
| 49 | } |
| 50 | if rowID, okR := idx.rowID[rowIdx]; okR { |
| 51 | if colID, okC := idx.colID[c]; okC { |
| 52 | v := h.Value(rowID, colID) |
| 53 | f := h.Format(rowID, colID) |
| 54 | cell.Raw, _ = h.RawInput(rowID, colID) |
| 55 | cell.Display = display(v, f) |
| 56 | cell.Number = v.Kind == calc.KindNum |
| 57 | cell.Paint = paintOf(f) |
| 58 | } |
| 59 | } |
| 60 | row.Cells = append(row.Cells, cell) |
| 61 | } |
| 62 | rows = append(rows, row) |
| 63 | } |
| 64 | return rows |
| 65 | } |
| 66 | |