Add clickable entities to tweet text

This commit is contained in:
Alessio 2023-08-27 15:09:35 -03:00
parent 11c94511d5
commit f8cd326440
4 changed files with 116 additions and 3 deletions

View 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")
}

View File

@ -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 {

View File

@ -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)

View File

@ -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">