mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-12 05:20:26 +00:00
Reimplement images
This commit is contained in:
parent
84a9f6bbf8
commit
c984790d3d
3
hypha.go
3
hypha.go
@ -32,6 +32,7 @@ func init() {
|
||||
}
|
||||
return
|
||||
}
|
||||
markup.HyphaIterate = IterateHyphaNamesWith
|
||||
}
|
||||
|
||||
// GetHyphaData finds a hypha addressed by `hyphaName` and returns its `hyphaData`. `hyphaData` is set to a zero value if this hypha does not exist. `isOld` is false if this hypha does not exist.
|
||||
@ -190,7 +191,7 @@ func binaryHtmlBlock(hyphaName string, hd *HyphaData) string {
|
||||
case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico":
|
||||
return fmt.Sprintf(`
|
||||
<div class="binary-container binary-container_with-img">
|
||||
<a href="/page/%[1]s"><img src="/binary/%[1]s"/></a>
|
||||
<a href="/binary/%[1]s"><img src="/binary/%[1]s"/></a>
|
||||
</div>`, hyphaName)
|
||||
case ".ogg", ".webm", ".mp4":
|
||||
return fmt.Sprintf(`
|
||||
|
2
main.go
2
main.go
@ -23,7 +23,7 @@ import (
|
||||
var WikiDir string
|
||||
|
||||
// HyphaPattern is a pattern which all hyphae must match.
|
||||
var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"\'&%]+`)
|
||||
var HyphaPattern = regexp.MustCompile(`[^?!:#@><*|"\'&%{}]+`)
|
||||
|
||||
// HyphaStorage is a mapping between canonical hypha names and their meta information.
|
||||
var HyphaStorage = make(map[string]*HyphaData)
|
||||
|
280
markup/img.go
280
markup/img.go
@ -13,53 +13,169 @@ func MatchesImg(line string) bool {
|
||||
}
|
||||
|
||||
type imgEntry struct {
|
||||
path string
|
||||
sizeH string
|
||||
sizeV string
|
||||
desc string
|
||||
trimmedPath string
|
||||
path strings.Builder
|
||||
sizeW strings.Builder
|
||||
sizeH strings.Builder
|
||||
desc strings.Builder
|
||||
}
|
||||
|
||||
func (entry *imgEntry) descriptionAsHtml(hyphaName string) (html string) {
|
||||
if entry.desc.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
lines := strings.Split(entry.desc.String(), "\n")
|
||||
for _, line := range lines {
|
||||
if line = strings.TrimSpace(line); line != "" {
|
||||
if html != "" {
|
||||
html += `<br>`
|
||||
}
|
||||
html += ParagraphToHtml(hyphaName, line)
|
||||
}
|
||||
}
|
||||
return `<figcaption>` + html + `</figcaption>`
|
||||
}
|
||||
|
||||
func (entry *imgEntry) sizeWAsAttr() string {
|
||||
if entry.sizeW.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
return ` width="` + entry.sizeW.String() + `"`
|
||||
}
|
||||
|
||||
func (entry *imgEntry) sizeHAsAttr() string {
|
||||
if entry.sizeH.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
return ` height="` + entry.sizeH.String() + `"`
|
||||
}
|
||||
|
||||
type imgState int
|
||||
|
||||
const (
|
||||
inRoot imgState = iota
|
||||
inName
|
||||
inDimensionsW
|
||||
inDimensionsH
|
||||
inDescription
|
||||
)
|
||||
|
||||
type Img struct {
|
||||
entries []imgEntry
|
||||
inDesc bool
|
||||
currEntry imgEntry
|
||||
hyphaName string
|
||||
state imgState
|
||||
}
|
||||
|
||||
func (img *Img) pushEntry() {
|
||||
if strings.TrimSpace(img.currEntry.path.String()) != "" {
|
||||
img.entries = append(img.entries, img.currEntry)
|
||||
img.currEntry = imgEntry{}
|
||||
img.currEntry.path.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func (img *Img) Process(line string) (shouldGoBackToNormal bool) {
|
||||
if img.inDesc {
|
||||
rightBraceIndex := strings.IndexRune(line, '}')
|
||||
if cnt := len(img.entries); rightBraceIndex == -1 && cnt != 0 {
|
||||
img.entries[cnt-1].desc += "\n" + line
|
||||
} else if rightBraceIndex != -1 && cnt != 0 {
|
||||
img.entries[cnt-1].desc += "\n" + line[:rightBraceIndex]
|
||||
img.inDesc = false
|
||||
}
|
||||
if strings.Count(line, "}") > 1 {
|
||||
stateToProcessor := map[imgState]func(rune) bool{
|
||||
inRoot: img.processInRoot,
|
||||
inName: img.processInName,
|
||||
inDimensionsW: img.processInDimensionsW,
|
||||
inDimensionsH: img.processInDimensionsH,
|
||||
inDescription: img.processInDescription,
|
||||
}
|
||||
for _, r := range line {
|
||||
if shouldReturnTrue := stateToProcessor[img.state](r); shouldReturnTrue {
|
||||
return true
|
||||
}
|
||||
} else if s := strings.TrimSpace(line); s != "" {
|
||||
if s[0] == '}' {
|
||||
return true
|
||||
}
|
||||
img.parseStartOfEntry(line)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ImgFromFirstLine(line, hyphaName string) Img {
|
||||
img := Img{
|
||||
func (img *Img) processInDescription(r rune) (shouldReturnTrue bool) {
|
||||
switch r {
|
||||
case '}':
|
||||
img.state = inName
|
||||
default:
|
||||
img.currEntry.desc.WriteRune(r)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (img *Img) processInRoot(r rune) (shouldReturnTrue bool) {
|
||||
switch r {
|
||||
case '}':
|
||||
img.pushEntry()
|
||||
return true
|
||||
case '\n', '\r':
|
||||
img.pushEntry()
|
||||
case ' ', '\t':
|
||||
default:
|
||||
img.state = inName
|
||||
img.currEntry = imgEntry{}
|
||||
img.currEntry.path.Reset()
|
||||
img.currEntry.path.WriteRune(r)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (img *Img) processInName(r rune) (shouldReturnTrue bool) {
|
||||
switch r {
|
||||
case '}':
|
||||
img.pushEntry()
|
||||
return true
|
||||
case '|':
|
||||
img.state = inDimensionsW
|
||||
case '{':
|
||||
img.state = inDescription
|
||||
case '\n', '\r':
|
||||
img.pushEntry()
|
||||
img.state = inRoot
|
||||
default:
|
||||
img.currEntry.path.WriteRune(r)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (img *Img) processInDimensionsW(r rune) (shouldReturnTrue bool) {
|
||||
switch r {
|
||||
case '}':
|
||||
img.pushEntry()
|
||||
return true
|
||||
case '*':
|
||||
img.state = inDimensionsH
|
||||
case ' ', '\t', '\n':
|
||||
case '{':
|
||||
img.state = inDescription
|
||||
default:
|
||||
img.currEntry.sizeW.WriteRune(r)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (img *Img) processInDimensionsH(r rune) (shouldGoBackToNormal bool) {
|
||||
switch r {
|
||||
case '}':
|
||||
img.pushEntry()
|
||||
return true
|
||||
case ' ', '\t', '\n':
|
||||
case '{':
|
||||
img.state = inDescription
|
||||
default:
|
||||
img.currEntry.sizeH.WriteRune(r)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ImgFromFirstLine(line, hyphaName string) (img *Img, shouldGoBackToNormal bool) {
|
||||
img = &Img{
|
||||
hyphaName: hyphaName,
|
||||
entries: make([]imgEntry, 0),
|
||||
}
|
||||
line = line[strings.IndexRune(line, '{'):]
|
||||
if len(line) == 1 { // if { only
|
||||
} else {
|
||||
line = line[1:] // Drop the {
|
||||
}
|
||||
return img
|
||||
line = line[strings.IndexRune(line, '{')+1:]
|
||||
return img, img.Process(line)
|
||||
}
|
||||
|
||||
func (img *Img) canonicalPathFor(path string) string {
|
||||
func (img *Img) binaryPathFor(path string) string {
|
||||
path = strings.TrimSpace(path)
|
||||
if strings.IndexRune(path, ':') != -1 || strings.IndexRune(path, '/') == 0 {
|
||||
return path
|
||||
@ -68,73 +184,71 @@ func (img *Img) canonicalPathFor(path string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (img *Img) parseStartOfEntry(line string) (entry imgEntry, followedByDesc bool) {
|
||||
pipeIndex := strings.IndexRune(line, '|')
|
||||
if pipeIndex == -1 { // If no : in string
|
||||
entry.path = img.canonicalPathFor(line)
|
||||
func (img *Img) pagePathFor(path string) string {
|
||||
path = strings.TrimSpace(path)
|
||||
if strings.IndexRune(path, ':') != -1 || strings.IndexRune(path, '/') == 0 {
|
||||
return path
|
||||
} else {
|
||||
entry.path = img.canonicalPathFor(line[:pipeIndex])
|
||||
line = strings.TrimPrefix(line, line[:pipeIndex+1])
|
||||
|
||||
var (
|
||||
leftBraceIndex = strings.IndexRune(line, '{')
|
||||
rightBraceIndex = strings.IndexRune(line, '}')
|
||||
dimensions string
|
||||
)
|
||||
|
||||
if leftBraceIndex == -1 {
|
||||
dimensions = line
|
||||
} else {
|
||||
dimensions = line[:leftBraceIndex]
|
||||
}
|
||||
|
||||
sizeH, sizeV := parseDimensions(dimensions)
|
||||
entry.sizeH = sizeH
|
||||
entry.sizeV = sizeV
|
||||
|
||||
if leftBraceIndex != -1 && rightBraceIndex == -1 {
|
||||
img.inDesc = true
|
||||
followedByDesc = true
|
||||
entry.desc = strings.TrimPrefix(line, line[:leftBraceIndex+1])
|
||||
} else if leftBraceIndex != -1 && rightBraceIndex != -1 {
|
||||
entry.desc = line[leftBraceIndex+1 : rightBraceIndex]
|
||||
}
|
||||
return "/page/" + xclCanonicalName(img.hyphaName, path)
|
||||
}
|
||||
img.entries = append(img.entries, entry)
|
||||
return
|
||||
}
|
||||
|
||||
func parseDimensions(dimensions string) (sizeH, sizeV string) {
|
||||
func parseDimensions(dimensions string) (sizeW, sizeH string) {
|
||||
xIndex := strings.IndexRune(dimensions, '*')
|
||||
if xIndex == -1 { // If no x in dimensions
|
||||
sizeH = strings.TrimSpace(dimensions)
|
||||
sizeW = strings.TrimSpace(dimensions)
|
||||
} else {
|
||||
sizeH = strings.TrimSpace(dimensions[:xIndex])
|
||||
sizeV = strings.TrimSpace(strings.TrimPrefix(dimensions, dimensions[:xIndex+1]))
|
||||
sizeW = strings.TrimSpace(dimensions[:xIndex])
|
||||
sizeH = strings.TrimSpace(strings.TrimPrefix(dimensions, dimensions[:xIndex+1]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (img Img) ToHtml() (html string) {
|
||||
for _, entry := range img.entries {
|
||||
html += fmt.Sprintf(`<figure>
|
||||
<img src="%s" width="%s" height="%s">
|
||||
`, entry.path, entry.sizeH, entry.sizeV)
|
||||
if entry.desc != "" {
|
||||
html += ` <figcaption>`
|
||||
for i, line := range strings.Split(entry.desc, "\n") {
|
||||
if line != "" {
|
||||
if i > 0 {
|
||||
html += `<br>`
|
||||
}
|
||||
html += ParagraphToHtml(img.hyphaName, line)
|
||||
}
|
||||
}
|
||||
html += `</figcaption>`
|
||||
func (img *Img) checkLinks() map[string]bool {
|
||||
m := make(map[string]bool)
|
||||
for i, entry := range img.entries {
|
||||
// Also trim them for later use
|
||||
entry.trimmedPath = strings.TrimSpace(entry.path.String())
|
||||
isAbsoluteUrl := strings.ContainsRune(entry.trimmedPath, ':')
|
||||
if !isAbsoluteUrl {
|
||||
entry.trimmedPath = canonicalName(entry.trimmedPath)
|
||||
}
|
||||
img.entries[i] = entry
|
||||
m[entry.trimmedPath] = isAbsoluteUrl
|
||||
}
|
||||
HyphaIterate(func(hyphaName string) {
|
||||
for _, entry := range img.entries {
|
||||
if hyphaName == entry.trimmedPath {
|
||||
m[entry.trimmedPath] = true
|
||||
}
|
||||
}
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
||||
func (img *Img) ToHtml() (html string) {
|
||||
linkAvailabilityMap := img.checkLinks()
|
||||
isOneImageOnly := len(img.entries) == 1 && img.entries[0].desc.Len() == 0
|
||||
if isOneImageOnly {
|
||||
html += `<section class="img-gallery img-gallery_one-image">`
|
||||
} else {
|
||||
html += `<section class="img-gallery img-gallery_many-images">`
|
||||
}
|
||||
|
||||
for _, entry := range img.entries {
|
||||
html += `<figure>`
|
||||
// If is existing hypha or an external path
|
||||
if linkAvailabilityMap[entry.trimmedPath] {
|
||||
html += fmt.Sprintf(
|
||||
`<a href="%s"><img src="%s" %s %s></a>`,
|
||||
img.pagePathFor(entry.trimmedPath),
|
||||
img.binaryPathFor(entry.trimmedPath),
|
||||
entry.sizeWAsAttr(), entry.sizeHAsAttr())
|
||||
} else { // If is a non-existent hypha
|
||||
html += fmt.Sprintf(`<a class="wikilink_new" href="%s">Hypha <em>%s</em> does not exist</a>`, img.pagePathFor(entry.trimmedPath), entry.trimmedPath)
|
||||
}
|
||||
html += entry.descriptionAsHtml(img.hyphaName)
|
||||
html += `</figure>`
|
||||
}
|
||||
return `<section class="img-gallery">
|
||||
` + html + `
|
||||
</section>`
|
||||
return html + `</section>`
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ var HyphaExists func(string) bool
|
||||
// HyphaAccess holds function that accesses a hypha by its name.
|
||||
var HyphaAccess func(string) (rawText, binaryHtml string, err error)
|
||||
|
||||
// HyphaIterate is a function that iterates all hypha names existing.
|
||||
var HyphaIterate func(func(string))
|
||||
|
||||
// GemLexerState is used by markup parser to remember what is going on.
|
||||
type GemLexerState struct {
|
||||
// Name of hypha being parsed
|
||||
@ -21,7 +24,7 @@ type GemLexerState struct {
|
||||
id int
|
||||
buf string
|
||||
// Temporaries
|
||||
img Img
|
||||
img *Img
|
||||
}
|
||||
|
||||
type Line struct {
|
||||
@ -84,7 +87,7 @@ func geminiLineToAST(line string, state *GemLexerState, ast *[]Line) {
|
||||
imgState:
|
||||
if shouldGoBackToNormal := state.img.Process(line); shouldGoBackToNormal {
|
||||
state.where = ""
|
||||
addLine(state.img)
|
||||
addLine(*state.img)
|
||||
}
|
||||
return
|
||||
|
||||
@ -174,8 +177,13 @@ normalState:
|
||||
case line == "----":
|
||||
*ast = append(*ast, Line{id: -1, contents: "<hr/>"})
|
||||
case MatchesImg(line):
|
||||
state.where = "img"
|
||||
state.img = ImgFromFirstLine(line, state.name)
|
||||
img, shouldGoBackToNormal := ImgFromFirstLine(line, state.name)
|
||||
if shouldGoBackToNormal {
|
||||
addLine(*img)
|
||||
} else {
|
||||
state.where = "img"
|
||||
state.img = img
|
||||
}
|
||||
default:
|
||||
addLine(fmt.Sprintf("<p id='%d'>%s</p>", state.id, ParagraphToHtml(state.name, line)))
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ func Parse(ast []Line, from, to int, state GemParserState) (html string) {
|
||||
html += v.ToHtml()
|
||||
case string:
|
||||
html += v
|
||||
default:
|
||||
html += "Unknown"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 41b572a78082e8eaa62a04937f95dad295039e8a
|
||||
Subproject commit 7828352598c19afe5f2e13df0219656ac7b44c9c
|
@ -34,8 +34,11 @@ article pre.codeblock {background-color:#eee; padding:.5rem; white-space: pre-wr
|
||||
.binary-container_with-video video,
|
||||
.binary-container_with-audio audio {width: 100%}
|
||||
.navi-title a {text-decoration:none;}
|
||||
.img-gallery img { max-width: 100%; }
|
||||
.img-gallery { text-align: center; margin-top: .25rem; }
|
||||
.img-gallery_many-images { background-color: #eee; border-radius: .25rem; padding: .5rem; }
|
||||
.img-gallery img { max-width: 100%; max-height: 50vh; }
|
||||
figure { margin: 0; }
|
||||
figcaption { padding-bottom: .5rem; }
|
||||
|
||||
nav ul {display:flex; padding-left:0; flex-wrap:wrap; margin-top:0;}
|
||||
nav ul li {list-style-type:none;margin-right:1rem;}
|
||||
|
@ -56,8 +56,11 @@ article pre.codeblock {background-color:#eee; padding:.5rem; white-space: pre-wr
|
||||
.binary-container_with-video video,
|
||||
.binary-container_with-audio audio {width: 100%}
|
||||
.navi-title a {text-decoration:none;}
|
||||
.img-gallery img { max-width: 100%; }
|
||||
.img-gallery { text-align: center; margin-top: .25rem; }
|
||||
.img-gallery_many-images { background-color: #eee; border-radius: .25rem; padding: .5rem; }
|
||||
.img-gallery img { max-width: 100%; max-height: 50vh; }
|
||||
figure { margin: 0; }
|
||||
figcaption { padding-bottom: .5rem; }
|
||||
|
||||
nav ul {display:flex; padding-left:0; flex-wrap:wrap; margin-top:0;}
|
||||
nav ul li {list-style-type:none;margin-right:1rem;}
|
||||
@ -71,31 +74,31 @@ nav ul li {list-style-type:none;margin-right:1rem;}
|
||||
.rc-entry__links { grid-column: 1 / span 2; }
|
||||
.rc-entry__author { font-style: italic; }
|
||||
`)
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
}
|
||||
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
func WriteDefaultCSS(qq422016 qtio422016.Writer) {
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
StreamDefaultCSS(qw422016)
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
}
|
||||
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
func DefaultCSS() string {
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
WriteDefaultCSS(qb422016)
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
qs422016 := string(qb422016.B)
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
return qs422016
|
||||
//line templates/css.qtpl:51
|
||||
//line templates/css.qtpl:54
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user