Added spoilers in chat
If a user clicks the spoiler, it will change color and the background will revert. closes #62
This commit is contained in:
parent
d419f64379
commit
86207ecd48
7
Makefile
7
Makefile
@ -1,8 +1,8 @@
|
||||
TAGS=
|
||||
|
||||
.PHONY: fmt vet get clean dev setdev
|
||||
.PHONY: fmt vet get clean dev setdev test
|
||||
|
||||
all: fmt vet MovieNight MovieNight.exe static/main.wasm
|
||||
all: fmt vet test MovieNight MovieNight.exe static/main.wasm
|
||||
|
||||
setdev:
|
||||
$(eval export TAGS=-tags "dev")
|
||||
@ -32,3 +32,6 @@ get:
|
||||
vet:
|
||||
go vet $(TAGS) ./...
|
||||
GOOS=js GOARCH=wasm go vet $(TAGS) ./...
|
||||
|
||||
test:
|
||||
go test $(TAGS) ./...
|
@ -10,6 +10,12 @@ import (
|
||||
"github.com/zorchenhimer/MovieNight/common"
|
||||
)
|
||||
|
||||
var (
|
||||
regexSpoiler = regexp.MustCompile(`\|\|(.*?)\|\|`)
|
||||
spoilerStart = `<span class="spoiler" onclick='$(this).removeClass("spoiler").addClass("spoiler-active")'>`
|
||||
spoilerEnd = `</span>`
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
name string // Display name
|
||||
conn *chatConnection
|
||||
@ -18,6 +24,7 @@ type Client struct {
|
||||
CmdLevel common.CommandLevel
|
||||
IsColorForced bool
|
||||
IsNameForced bool
|
||||
regexName *regexp.Regexp
|
||||
}
|
||||
|
||||
//Client has a new message to broadcast
|
||||
@ -49,6 +56,10 @@ func (cl *Client) NewMsg(data common.ClientData) {
|
||||
msg = removeDumbSpaces(msg)
|
||||
msg = strings.Trim(msg, " ")
|
||||
|
||||
// Add the spoiler tag outside of the command vs message statement
|
||||
// because the /me command outputs to the messages
|
||||
msg = addSpoilerTags(msg)
|
||||
|
||||
// Don't send zero-length messages
|
||||
if len(msg) == 0 {
|
||||
return
|
||||
@ -94,7 +105,11 @@ func (cl *Client) NewMsg(data common.ClientData) {
|
||||
func (cl *Client) SendChatData(data common.ChatData) error {
|
||||
// Colorize name on chat messages
|
||||
if data.Type == common.DTChat {
|
||||
data = replaceColorizedName(data, cl)
|
||||
var err error
|
||||
data = cl.replaceColorizedName(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not colorize name: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
cd, err := data.ToJSON()
|
||||
@ -164,6 +179,24 @@ func (cl *Client) Host() string {
|
||||
return cl.conn.Host()
|
||||
}
|
||||
|
||||
func (cl *Client) setName(s string) error {
|
||||
regex, err := regexp.Compile(fmt.Sprintf("(%s|@%s)", s, s))
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not compile regex: %v", err)
|
||||
}
|
||||
|
||||
cl.name = s
|
||||
cl.regexName = regex
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *Client) replaceColorizedName(chatData common.ChatData) common.ChatData {
|
||||
data := chatData.Data.(common.DataMessage)
|
||||
data.Message = cl.regexName.ReplaceAllString(data.Message, `<span class="mention">$1</span>`)
|
||||
chatData.Data = data
|
||||
return chatData
|
||||
}
|
||||
|
||||
var dumbSpaces = []string{
|
||||
"\n",
|
||||
"\t",
|
||||
@ -187,12 +220,6 @@ func removeDumbSpaces(msg string) string {
|
||||
return newMsg
|
||||
}
|
||||
|
||||
func replaceColorizedName(chatData common.ChatData, client *Client) common.ChatData {
|
||||
data := chatData.Data.(common.DataMessage)
|
||||
|
||||
data.Message = regexp.MustCompile(fmt.Sprintf(`(%s|@%s)`, client.name, client.name)).
|
||||
ReplaceAllString(data.Message, `<span class="mention">$1</span>`)
|
||||
|
||||
chatData.Data = data
|
||||
return chatData
|
||||
func addSpoilerTags(msg string) string {
|
||||
return regexSpoiler.ReplaceAllString(msg, fmt.Sprintf(`%s$1%s`, spoilerStart, spoilerEnd))
|
||||
}
|
||||
|
23
chatclient_test.go
Normal file
23
chatclient_test.go
Normal file
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestClient_addSpoilerTag(t *testing.T) {
|
||||
data := [][]string{
|
||||
{"||||", spoilerStart + spoilerEnd},
|
||||
{"|||||", spoilerStart + spoilerEnd + "|"},
|
||||
{"||||||", spoilerStart + spoilerEnd + "||"},
|
||||
{"|||||||", spoilerStart + spoilerEnd + "|||"},
|
||||
{"||||||||", spoilerStart + spoilerEnd + spoilerStart + spoilerEnd},
|
||||
{"||test||", spoilerStart + "test" + spoilerEnd},
|
||||
{"|| ||", spoilerStart + " " + spoilerEnd},
|
||||
{"|s|||", "|s|||"},
|
||||
}
|
||||
|
||||
for i := range data {
|
||||
s := addSpoilerTags(data[i][0])
|
||||
if s != data[i][1] {
|
||||
t.Errorf("expected %#v, got %#v with %#v", data[i][1], s, data[i][0])
|
||||
}
|
||||
}
|
||||
}
|
11
chatroom.go
11
chatroom.go
@ -98,12 +98,16 @@ func (cr *ChatRoom) Join(name, uid string) (*Client, error) {
|
||||
|
||||
conn.clientName = name
|
||||
client := &Client{
|
||||
name: name,
|
||||
conn: conn,
|
||||
belongsTo: cr,
|
||||
color: common.RandomColor(),
|
||||
}
|
||||
|
||||
err := client.setName(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not set client name to %#v: %v", name, err)
|
||||
}
|
||||
|
||||
host := client.Host()
|
||||
|
||||
if banned, names := settings.IsBanned(host); banned {
|
||||
@ -483,7 +487,10 @@ func (cr *ChatRoom) changeName(oldName, newName string, forced bool) error {
|
||||
}
|
||||
|
||||
if currentClient != nil {
|
||||
currentClient.name = newName
|
||||
err := currentClient.setName(newName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not set client name to %#v: %v", newName, err)
|
||||
}
|
||||
common.LogDebugf("%q -> %q\n", oldName, newName)
|
||||
|
||||
if forced {
|
||||
|
@ -42,6 +42,10 @@ var colors = []string{
|
||||
"whitesmoke", "yellow", "yellowgreen",
|
||||
}
|
||||
|
||||
var (
|
||||
regexColor = regexp.MustCompile(`^#([0-9A-Fa-f]{3}){1,2}$`)
|
||||
)
|
||||
|
||||
// IsValidColor takes a string s and compares it against a list of css color names.
|
||||
// It also accepts hex codes in the form of #000 (RGB), to #00000000 (RRGGBBAA), with A
|
||||
// being the alpha value
|
||||
@ -53,7 +57,7 @@ func IsValidColor(s string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if regexp.MustCompile(`^#([0-9A-Fa-f]{3}){1,2}$`).MatchString(s) {
|
||||
if regexColor.MatchString(s) {
|
||||
c, err := colorful.Hex(s)
|
||||
if err != nil {
|
||||
return false
|
||||
|
@ -23,7 +23,6 @@ const (
|
||||
logPrefixChat string = "[CHAT] "
|
||||
logPrefixInfo string = "[INFO] "
|
||||
logPrefixDebug string = "[DEBUG] "
|
||||
logPrefixDev string = "[DEV] "
|
||||
)
|
||||
|
||||
var (
|
||||
@ -31,18 +30,8 @@ var (
|
||||
logChat *log.Logger
|
||||
logInfo *log.Logger
|
||||
logDebug *log.Logger
|
||||
logDev *log.Logger
|
||||
)
|
||||
|
||||
//func ParseLogLevel(input string) LogLevel {
|
||||
// switch LogLevel(input) {
|
||||
// case LLError, LLChat, LLInfo, LLDebug:
|
||||
// return LogLevel(input)
|
||||
// default:
|
||||
// return LLError
|
||||
// }
|
||||
//}
|
||||
|
||||
func SetupLogging(level LogLevel, file string) error {
|
||||
switch level {
|
||||
case LLDebug:
|
||||
|
@ -2,18 +2,21 @@
|
||||
|
||||
package common
|
||||
|
||||
func LogDevf(format string, v ...interface{}) {
|
||||
if logError == nil {
|
||||
panic("Logging not setup!")
|
||||
}
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
logError.Printf(format, v...)
|
||||
var logDev *log.Logger
|
||||
|
||||
func init() {
|
||||
logDev = log.New(os.Stdout, "[DEV]", log.LstdFlags)
|
||||
}
|
||||
|
||||
func LogDevf(format string, v ...interface{}) {
|
||||
logDev.Printf(format, v...)
|
||||
}
|
||||
|
||||
func LogDevln(v ...interface{}) {
|
||||
if logError == nil {
|
||||
panic("Logging not setup!")
|
||||
}
|
||||
|
||||
logError.Println(v...)
|
||||
logDev.Println(v...)
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ func init() {
|
||||
panic("Missing stream key is settings.json")
|
||||
}
|
||||
|
||||
if err = common.SetupLogging(settings.LogLevel, settings.LogFile); err != nil {
|
||||
if err = settings.SetupLogging(); err != nil {
|
||||
panic("Unable to setup logger: " + err.Error())
|
||||
}
|
||||
|
||||
@ -184,3 +184,7 @@ func (s *Settings) GetStreamKey() string {
|
||||
}
|
||||
return s.StreamKey
|
||||
}
|
||||
|
||||
func (s *Settings) SetupLogging() error {
|
||||
return common.SetupLogging(s.LogLevel, s.LogFile)
|
||||
}
|
||||
|
@ -116,6 +116,22 @@ span.svmsg {
|
||||
color: var(--var-contrast-color);
|
||||
}
|
||||
|
||||
.spoiler {
|
||||
border-radius: 3px;
|
||||
padding: 0px 3px;
|
||||
}
|
||||
|
||||
.spoiler *,
|
||||
.spoiler {
|
||||
background: var(--var-popout-color);
|
||||
color: var(--var-popout-color);
|
||||
}
|
||||
|
||||
.spoiler-active {
|
||||
background: var(--var-background-color);
|
||||
color: aqua;
|
||||
}
|
||||
|
||||
.range-div {
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
|
Loading…
Reference in New Issue
Block a user