Add clickable entities to tweet text
This commit is contained in:
parent
11c94511d5
commit
f8cd326440
46
internal/webserver/helpers_test.go
Normal file
46
internal/webserver/helpers_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
package webserver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
// "fmt"
|
||||
// "net/http"
|
||||
// "net/http/httptest"
|
||||
// "net/url"
|
||||
// "strings"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetEntitiesNone(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
s := "This is just a simple string"
|
||||
entities := get_entities(s)
|
||||
|
||||
require.Len(entities, 1)
|
||||
assert.Equal(ENTITY_TYPE_TEXT, entities[0].EntityType)
|
||||
assert.Equal(s, entities[0].Contents)
|
||||
}
|
||||
|
||||
func TestGetEntitiesHashtagAndMention(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
s := "A string with a #hashtag and a @mention in it"
|
||||
entities := get_entities(s)
|
||||
|
||||
require.Len(entities, 5)
|
||||
assert.Equal(entities[0].EntityType, ENTITY_TYPE_TEXT)
|
||||
assert.Equal(entities[0].Contents, "A string with a ")
|
||||
assert.Equal(entities[1].EntityType, ENTITY_TYPE_HASHTAG)
|
||||
assert.Equal(entities[1].Contents, "hashtag")
|
||||
assert.Equal(entities[2].EntityType, ENTITY_TYPE_TEXT)
|
||||
assert.Equal(entities[2].Contents, " and a ")
|
||||
assert.Equal(entities[3].EntityType, ENTITY_TYPE_MENTION)
|
||||
assert.Equal(entities[3].Contents, "mention")
|
||||
assert.Equal(entities[4].EntityType, ENTITY_TYPE_TEXT)
|
||||
assert.Equal(entities[4].Contents, " in it")
|
||||
}
|
@ -9,6 +9,7 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
|
||||
@ -91,6 +92,7 @@ func (app *Application) buffered_render_tweet_page(w http.ResponseWriter, tpl_fi
|
||||
"space": data.Space,
|
||||
"active_user": app.get_active_user,
|
||||
"focused_tweet_id": data.FocusedTweetID,
|
||||
"get_entities": get_entities,
|
||||
}),
|
||||
Filenames: append(partials, get_filepath(tpl_file)),
|
||||
TplName: "base",
|
||||
@ -124,6 +126,7 @@ func (app *Application) buffered_render_tweet_htmx(w http.ResponseWriter, tpl_na
|
||||
"space": data.Space,
|
||||
"active_user": app.get_active_user,
|
||||
"focused_tweet_id": data.FocusedTweetID,
|
||||
"get_entities": get_entities,
|
||||
}),
|
||||
Filenames: partials,
|
||||
TplName: tpl_name,
|
||||
@ -148,6 +151,41 @@ func (app *Application) get_active_user() scraper.User {
|
||||
return app.ActiveUser
|
||||
}
|
||||
|
||||
type EntityType int
|
||||
|
||||
const (
|
||||
ENTITY_TYPE_TEXT EntityType = iota
|
||||
ENTITY_TYPE_MENTION
|
||||
ENTITY_TYPE_HASHTAG
|
||||
)
|
||||
|
||||
type Entity struct {
|
||||
EntityType
|
||||
Contents string
|
||||
}
|
||||
|
||||
func get_entities(text string) []Entity {
|
||||
ret := []Entity{}
|
||||
start := 0
|
||||
for _, idxs := range regexp.MustCompile(`[@#]\w+`).FindAllStringIndex(text, -1) {
|
||||
if start != idxs[0] {
|
||||
ret = append(ret, Entity{ENTITY_TYPE_TEXT, text[start:idxs[0]]})
|
||||
}
|
||||
piece := text[idxs[0]+1 : idxs[1]] // Chop off the "#" or "@"
|
||||
if text[idxs[0]] == '@' {
|
||||
ret = append(ret, Entity{ENTITY_TYPE_MENTION, piece})
|
||||
} else {
|
||||
ret = append(ret, Entity{ENTITY_TYPE_HASHTAG, piece})
|
||||
}
|
||||
start = idxs[1]
|
||||
}
|
||||
if start < len(text) {
|
||||
ret = append(ret, Entity{ENTITY_TYPE_TEXT, text[start:]})
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func func_map(extras template.FuncMap) template.FuncMap {
|
||||
ret := sprig.FuncMap()
|
||||
for i := range extras {
|
||||
|
@ -318,6 +318,24 @@ func TestTweetsWithContent(t *testing.T) {
|
||||
assert.Len(cascadia.QueryAll(root, selector("ul.space-participants-list li")), 9)
|
||||
}
|
||||
|
||||
func TestTweetWithEntities(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
resp := do_request(httptest.NewRequest("GET", "/tweet/1489944024278523906", nil))
|
||||
require.Equal(resp.StatusCode, 200)
|
||||
root, err := html.Parse(resp.Body)
|
||||
require.NoError(err)
|
||||
entities := cascadia.QueryAll(root, selector(".entity"))
|
||||
assert.Len(entities, 2)
|
||||
assert.Equal(entities[0].Data, "a")
|
||||
assert.Equal(entities[0].FirstChild.Data, "@gofundme")
|
||||
assert.Contains(entities[0].Attr, html.Attribute{Key: "href", Val: "/gofundme"})
|
||||
assert.Equal(entities[1].Data, "a")
|
||||
assert.Equal(entities[1].FirstChild.Data, "#BankruptGoFundMe")
|
||||
assert.Contains(entities[1].Attr, html.Attribute{Key: "href", Val: "/search/%23BankruptGoFundMe"})
|
||||
}
|
||||
|
||||
func TestLongTweet(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
@ -51,8 +51,19 @@
|
||||
<span class="vertical-container-1">
|
||||
<div class="tweet-content">
|
||||
{{range (splitList "\n" $main_tweet.Text)}}
|
||||
<p class="tweet-text">
|
||||
{{.}}
|
||||
<p class="tweet-text" hx-trigger="click consume">
|
||||
{{range (get_entities .)}}
|
||||
{{if (eq .EntityType 1)}}
|
||||
<!-- Mention -->
|
||||
<a class="entity" href="/{{.Contents}}">@{{.Contents}}</a>
|
||||
{{else if (eq .EntityType 2)}}
|
||||
<!-- Hashtag -->
|
||||
<a class="entity" href="/search/%23{{.Contents}}">#{{.Contents}}</a>
|
||||
{{else}}
|
||||
<!-- Just text -->
|
||||
{{.Contents}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</p>
|
||||
{{end}}
|
||||
|
||||
@ -114,7 +125,7 @@
|
||||
</div>
|
||||
<div class="dummy"></div>
|
||||
<div class="dropdown" hx-trigger="click consume">
|
||||
<button class="dropdown-button">
|
||||
<button class="dropdown-button" title="Options">
|
||||
<img class="svg-icon" src="/static/icons/more.svg" />
|
||||
</button>
|
||||
<ul class="dropdown-items">
|
||||
|
Loading…
x
Reference in New Issue
Block a user