vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
| 1 | package web |
| 2 | |
| 3 | // The functions a template may call. They are one list, registered as a set, so |
| 4 | // a template's vocabulary is finite and reviewable: nothing in a page reaches |
| 5 | // past these into the package. |
| 6 | // |
| 7 | // Two rules keep them honest. Nothing here authorizes anything — a template only |
| 8 | // renders what a handler already decided. And nothing here is allowed to fail: |
| 9 | // a template function has no error path, so a helper that cannot answer returns |
| 10 | // an empty string or a zero value. |
| 11 | |
| 12 | import ( |
| 13 | "html/template" |
| 14 | "net/url" |
| 15 | "strings" |
| 16 | |
| 17 | "rodent.software/vole/forge/identity" |
| 18 | "rodent.software/vole/internal/format" |
| 19 | "rodent.software/vole/internal/lang" |
| 20 | ) |
| 21 | |
| 22 | // templateFuncs is a method rather than a plain map because two helpers need the |
| 23 | // roster the Web holds. It is called once, in New, before the templates are |
| 24 | // parsed. |
| 25 | func (w *Web) templateFuncs() template.FuncMap { |
| 26 | return template.FuncMap{ |
| 27 | // Formatting. `since` takes a Unix second so a template does not have to |
| 28 | // convert; `short` and `bytes` are the same renderings the CLI uses. |
| 29 | "since": humanSince, |
| 30 | "short": format.SHA, |
| 31 | "num": numberLabel, |
| 32 | "bytes": format.Bytes, |
| 33 | "duration": format.Duration, |
| 34 | // runstatus is the stored status as a reader should see it. The value itself is |
| 35 | // the key the gate and the list filters use. |
| 36 | "runstatus": runStatusLabel, |
| 37 | "credid": identity.CredentialIDString, |
| 38 | "inc": func(i int) int { return i + 1 }, |
| 39 | "join": strings.Join, |
| 40 | |
| 41 | // Escaping. They are not interchangeable: `esc` escapes a whole value |
| 42 | // (a ref or a query value, where a "/" becomes a segment separator), |
| 43 | // while `pathurl` escapes a slash-separated path segment by segment and |
| 44 | // keeps the separators. Using one where the other belongs produces a |
| 45 | // link that looks right and resolves to the wrong object. |
| 46 | "esc": url.PathEscape, |
| 47 | "pathurl": pathURL, |
| 48 | "urlquery": url.QueryEscape, |
| 49 | |
| 50 | // Chrome. `who` renders an account name and `user` the same name with the |
| 51 | // profile it belongs to; `nav` is the repository header's data, |
| 52 | // `icon`/`fileicon`/`fileclass` choose inline SVG and its colour. |
| 53 | "who": w.who, |
| 54 | "user": w.userRef, |
| 55 | "nav": w.repoNav, |
| 56 | "icon": icon, |
| 57 | "fileicon": fileIcon, |
| 58 | "fileclass": lang.Class, |
| 59 | |
| 60 | // People. The two pickers are the only widgets a page builds from data |
| 61 | // rather than a fragment. |
| 62 | "tokenPicker": tokenPicker, |
| 63 | "rolePicker": newRolePicker, |
| 64 | |
| 65 | // The file tree is recursive, so its context is built by a function: |
| 66 | // a template cannot construct the struct it passes back into itself. |
| 67 | "treeContext": treeContext, |
| 68 | "commitTreeContext": commitTreeContext, |
| 69 | "pathjoin": joinPath, |
| 70 | } |
| 71 | } |
| 72 |