diff options
Diffstat (limited to 'vrsite/page.go')
| -rw-r--r-- | vrsite/page.go | 84 |
1 files changed, 81 insertions, 3 deletions
diff --git a/vrsite/page.go b/vrsite/page.go index 2974eec..cca0c58 100644 --- a/vrsite/page.go +++ b/vrsite/page.go @@ -16,7 +16,7 @@ import ( type page struct { Site *Site Title string - Kind string // index | file | files | notes | jj | change | session + Kind string // index | file | files | notes | note | jj | change | session Root string // static: relative prefix; live: "/" Live bool Rev string // revision being browsed ("" = the change the log points at) @@ -40,6 +40,14 @@ type page struct { File *File Files []*File // every file at this change, for counts + // one note on its own page — the permalink. Excerpt is the code it is + // about, already rendered; ExErr says why there is none. + Note *Note + Thread *ThreadNode + Excerpt template.HTML + ExFrom, ExTo int + ExErr string + Notes []*Note Filter NoteFilter Facets *Facets @@ -105,7 +113,7 @@ func (p *page) BackHref() string { // that can be read at any change, the file tree otherwise. func (p *page) JumpPath() string { switch p.Kind { - case "index", "file", "files", "notes": + case "index", "file", "files", "notes", "note": if p.Path != "" { return p.Path } @@ -134,6 +142,8 @@ func (p *page) Href(kind string, arg ...string) string { return "/jj" case "code": return "/code/" + escPath(a) + p.params() + case "note": + return "/note/" + a case "change": return "/change/" + a case "session": @@ -154,6 +164,8 @@ func (p *page) Href(kind string, arg ...string) string { return p.Root + "tree.html" case "code": return p.Root + "code/" + a + ".html" + case "note": + return p.Root + "note/" + a + ".html" case "asset": return p.Root + a } @@ -184,6 +196,67 @@ func (p *page) ConvHref(n *Note) string { return p.Href("session", n.Session) + "?note=" + id + "#note-" + id } +// PermaHref is the note's own page: the link to hand someone else. It is the +// one link on the card that names nothing but the note, so it survives the +// change scope, the filters, and the file having moved on since. +// +// It is empty on the note's own page, which is where it already points, and in +// a static export of a different change, which has no page for it. +func (p *page) PermaHref(n *Note) string { + if p.Kind == "note" && (p.Note == nil || p.Note.ID == n.ID) { + return "" + } + if !p.Live && p.Site != nil && p.Site.NoteByID(n.ID) == nil { + return "" + } + return p.Href("note", strconv.Itoa(n.ID)) +} + +// ThreadHref opens the incoming replies and mentions for a note. The focused +// root only needs an in-page jump; every other card gets its own permalink. +func (p *page) ThreadHref(n *Note) string { + if len(n.Replies) == 0 && len(n.Mentions) == 0 { + return "" + } + if p.Kind == "note" && p.Note != nil && p.Note.ID == n.ID { + return "#discussion" + } + h := p.Href("note", strconv.Itoa(n.ID)) + if h == "" { + return "" + } + return h + "#discussion" +} + +// ReplyHref is the explicit parent link. A static export may not contain the +// parent's change, in which case it leaves the relationship as text instead of +// manufacturing a link to a page the export did not write. +func (p *page) ReplyHref(n *Note) string { + if n.ReplyTo < 1 { + return "" + } + if !p.Live && p.Site != nil && p.Site.NoteByID(n.ReplyTo) == nil { + return "" + } + return p.Href("note", strconv.Itoa(n.ReplyTo)) +} + +// HasCode reports whether this view has a page for a path. The live app can +// render any file at the change it is reading; a static export only wrote the +// ones present at the change it holds, so a note about a file that is not +// there must not offer a link into nothing. +func (p *page) HasCode(path string) bool { + if p.Live { + return path != "" + } + for _, f := range p.Files { + if f.Path == path { + return true + } + } + return false +} + // NoteHref points at the noted line, or the note list when it is unpinned. // The ?note= is what turns a jump into an arrival: the page opens in notes // focus with the card flashed and its lines marked (see app.js). @@ -204,9 +277,14 @@ func (p *page) NoteHref(n *Note) string { return h } -func newTemplates() *template.Template { +// newTemplates parses the page templates. The highlighter comes along because +// note bodies are markdown, and a fenced code block in a note is painted by +// the same grammars as the code view. +func newTemplates(hl *highlighter) *template.Template { + md := newMarkdown(hl) funcs := template.FuncMap{ "short": short, + "md": md.renderAt, "band": func(a, b uint8) bool { return b != 0 && a&b != 0 }, "lines": func(n *Note) string { if n.Start <= 0 { |
