mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-11 21:10:26 +00:00
Add anchor links
This commit is contained in:
parent
f45758cb0e
commit
fbf94975aa
@ -134,6 +134,9 @@ blockquote { margin-left: 0; padding-left: 1rem; }
|
||||
|
||||
article { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; line-height: 150%; }
|
||||
main h1, main h2, main h3, main h4, main h5, main h6 { margin: 1.5rem 0 0 0; }
|
||||
.heading__link { text-decoration: none; display: inline-block; }
|
||||
.heading__link::after { width: 1rem; content: "§"; color: transparent; }
|
||||
.heading__link:hover::after, .heading__link:active::after { color: #999; }
|
||||
article p { margin: .5rem 0; }
|
||||
article ul, ol { padding-left: 1.5rem; margin: .5rem 0; }
|
||||
article code { padding: .1rem .3rem; border-radius: .25rem; font-size: 90%; }
|
||||
@ -291,12 +294,7 @@ mark { background: rgba(130, 80, 30, 5); color: inherit; }
|
||||
@media screen and (max-width: 800px) {
|
||||
.hypha-tabs { background-color: #232323; }
|
||||
}
|
||||
@media screen and (min-width: 801px) {
|
||||
/* .hypha-tabs__tab { border: 1px #ddd solid; } */
|
||||
/* .hypha-tabs__tab_active { border-bottom: 1px white solid; } */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.backlinks { display: none; }
|
||||
`)
|
||||
|
@ -109,6 +109,9 @@ blockquote { margin-left: 0; padding-left: 1rem; }
|
||||
|
||||
article { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; line-height: 150%; }
|
||||
main h1, main h2, main h3, main h4, main h5, main h6 { margin: 1.5rem 0 0 0; }
|
||||
.heading__link { text-decoration: none; display: inline-block; }
|
||||
.heading__link::after { width: 1rem; content: "§"; color: transparent; }
|
||||
.heading__link:hover::after, .heading__link:active::after { color: #999; }
|
||||
article p { margin: .5rem 0; }
|
||||
article ul, ol { padding-left: 1.5rem; margin: .5rem 0; }
|
||||
article code { padding: .1rem .3rem; border-radius: .25rem; font-size: 90%; }
|
||||
@ -266,11 +269,6 @@ mark { background: rgba(130, 80, 30, 5); color: inherit; }
|
||||
@media screen and (max-width: 800px) {
|
||||
.hypha-tabs { background-color: #232323; }
|
||||
}
|
||||
@media screen and (min-width: 801px) {
|
||||
/* .hypha-tabs__tab { border: 1px #ddd solid; } */
|
||||
/* .hypha-tabs__tab_active { border-bottom: 1px white solid; } */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.backlinks { display: none; }
|
||||
|
@ -88,6 +88,10 @@ func (h *Hypha) Delete() {
|
||||
DecrementCount()
|
||||
byNamesMutex.Unlock()
|
||||
h.Unlock()
|
||||
|
||||
for _, outlinkHypha := range h.OutLinks {
|
||||
outlinkHypha.DropBackLink(h)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Hypha) RenameTo(newName string) {
|
||||
@ -113,7 +117,16 @@ func (h *Hypha) MergeIn(oh *Hypha) {
|
||||
}
|
||||
}
|
||||
|
||||
// Link related stuff:
|
||||
// ## Link related stuff
|
||||
// Notes in pseudocode and whatnot:
|
||||
// * (Reader h) does not mutate h => safe
|
||||
// * (Rename h) reuses the same hypha object => safe
|
||||
// * (Unattach h) and (Attach h) do not change (Backlinks h) => safe
|
||||
|
||||
// * (Delete h) does not change (Backlinks h), but changes (Outlinks h), removing h from them => make it safe
|
||||
// * (Unattach h) and (Attach h) => h may start or stop existing => may change (Outlinks h) => make it safe
|
||||
// * (Edit h) => h may start existing => may change (Backlinks h) => make it safe
|
||||
// * (Edit h) may add or remove h to or from (Outlinks h) => make it safe
|
||||
|
||||
func (h *Hypha) AddOutLink(oh *Hypha) (added bool) {
|
||||
h.Lock()
|
||||
@ -140,3 +153,23 @@ func (h *Hypha) AddBackLink(bh *Hypha) (added bool) {
|
||||
h.BackLinks = append(h.BackLinks, bh)
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *Hypha) DropBackLink(bh *Hypha) {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
|
||||
if len(h.BackLinks) <= 1 {
|
||||
h.BackLinks = make([]*Hypha, 0)
|
||||
return
|
||||
}
|
||||
lastBackLinkIndex := len(h.BackLinks)
|
||||
for i, backlink := range h.BackLinks {
|
||||
if backlink == bh {
|
||||
if i != lastBackLinkIndex {
|
||||
h.BackLinks[i] = h.BackLinks[lastBackLinkIndex]
|
||||
}
|
||||
h.BackLinks = h.BackLinks[:lastBackLinkIndex]
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ type Link struct {
|
||||
Kind LinkType
|
||||
DestinationUnknown bool
|
||||
|
||||
// #...
|
||||
Anchor string
|
||||
Protocol string
|
||||
// How the link address looked originally in source text.
|
||||
SrcAddress string
|
||||
@ -66,7 +68,7 @@ func (l *Link) Href() string {
|
||||
case LinkExternal, LinkLocalRoot:
|
||||
return l.Address
|
||||
default:
|
||||
return "/hypha/" + l.Address
|
||||
return "/hypha/" + l.Address + l.Anchor
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,6 +119,10 @@ func From(address, display, hyphaName string) *Link {
|
||||
case strings.HasPrefix(address, "../"):
|
||||
link.Kind = LinkLocalHypha
|
||||
link.Address = util.CanonicalName(path.Join(path.Dir(hyphaName), address[3:]))
|
||||
case strings.HasPrefix(address, "#"):
|
||||
link.Kind = LinkLocalHypha
|
||||
link.Address = util.CanonicalName(hyphaName)
|
||||
link.Anchor = address
|
||||
default:
|
||||
link.Kind = LinkLocalHypha
|
||||
link.Address = util.CanonicalName(address)
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"html"
|
||||
"strings"
|
||||
|
||||
"github.com/bouncepaw/mycorrhiza/util"
|
||||
)
|
||||
|
||||
// HyphaExists holds function that checks that a hypha is present.
|
||||
@ -83,7 +85,8 @@ func lineToAST(line string, state *GemLexerState, ast *[]Line) {
|
||||
return strings.HasPrefix(line, token)
|
||||
}
|
||||
addHeading := func(i int) {
|
||||
addLine(fmt.Sprintf("<h%d id='%d'>%s</h%d>", i, state.id, ParagraphToHtml(state.name, line[i+1:]), i))
|
||||
id := util.LettersNumbersOnly(line[i+1:])
|
||||
addLine(fmt.Sprintf(`<h%d id='%d'>%s<a href="#%s" id="%s" class="heading__link"></a></h%d>`, i, state.id, ParagraphToHtml(state.name, line[i+1:]), id, id, i))
|
||||
}
|
||||
|
||||
// Beware! Usage of goto. Some may say it is considered evil but in this case it helped to make a better-structured code.
|
||||
|
@ -89,7 +89,7 @@ func renamingPairs(hyphaeToRename []*hyphae.Hypha, replaceName func(string) stri
|
||||
renameMap := make(map[string]string)
|
||||
newNames := make([]string, len(hyphaeToRename))
|
||||
for _, h := range hyphaeToRename {
|
||||
h.RLock()
|
||||
h.Lock()
|
||||
newNames = append(newNames, replaceName(h.Name))
|
||||
if h.TextPath != "" {
|
||||
renameMap[h.TextPath] = replaceName(h.TextPath)
|
||||
@ -97,7 +97,7 @@ func renamingPairs(hyphaeToRename []*hyphae.Hypha, replaceName func(string) stri
|
||||
if h.BinaryPath != "" {
|
||||
renameMap[h.BinaryPath] = replaceName(h.BinaryPath)
|
||||
}
|
||||
h.RUnlock()
|
||||
h.Unlock()
|
||||
}
|
||||
if firstFailure, ok := hyphae.AreFreeNames(newNames...); !ok {
|
||||
return nil, errors.New("Hypha " + firstFailure + " already exists")
|
||||
|
19
util/util.go
19
util/util.go
@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -22,6 +23,24 @@ var (
|
||||
GeminiCertPath string
|
||||
)
|
||||
|
||||
// LettersNumbersOnly keeps letters and numbers only in the given string.
|
||||
func LettersNumbersOnly(s string) string {
|
||||
var (
|
||||
ret strings.Builder
|
||||
usedUnderscore bool
|
||||
)
|
||||
for _, r := range s {
|
||||
if unicode.IsLetter(r) || unicode.IsNumber(r) {
|
||||
ret.WriteRune(r)
|
||||
usedUnderscore = false
|
||||
} else if !usedUnderscore {
|
||||
ret.WriteRune('_')
|
||||
usedUnderscore = true
|
||||
}
|
||||
}
|
||||
return strings.Trim(ret.String(), "_")
|
||||
}
|
||||
|
||||
// ShorterPath is used by handlerList to display shorter path to the files. It simply strips WikiDir.
|
||||
func ShorterPath(path string) string {
|
||||
if strings.HasPrefix(path, WikiDir) {
|
||||
|
Loading…
Reference in New Issue
Block a user