dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

codeModal.go (5311B)


      1 package streamModals
      2 
      3 import (
      4 	"bytes"
      5 	"dkforest/pkg/database"
      6 	"dkforest/pkg/utils"
      7 	"dkforest/pkg/web/handlers/interceptors/command"
      8 	"html/template"
      9 	"strconv"
     10 	"strings"
     11 )
     12 
     13 const name = "code"
     14 
     15 var langs = [][]string{
     16 	{"", "Raw text"},
     17 	{"go", "Golang"},
     18 	{"rs", "Rust"},
     19 	{"cpp", "C++"},
     20 	{"c", "C"},
     21 	{"py", "Python"},
     22 	{"js", "Javascript"},
     23 	{"php", "PHP"},
     24 	{"css", "CSS"},
     25 	{"sql", "SQL"},
     26 	{"c#", "C#"},
     27 	{"rb", "Ruby"},
     28 	{"html", "HTML"},
     29 	{"bash", "Bash"},
     30 }
     31 
     32 type CodeModal struct {
     33 	StreamModal
     34 }
     35 
     36 func (m CodeModal) Show(userID database.UserID, roomID database.RoomID, payload database.ChatMessageType) {
     37 	database.MsgPubSub.Pub(m.showTopic(name, userID, roomID), payload)
     38 }
     39 
     40 func (m CodeModal) Hide(userID database.UserID, roomID database.RoomID) {
     41 	database.MsgPubSub.Pub(m.hideTopic(name, userID, roomID), database.ChatMessageType{})
     42 }
     43 
     44 func NewCodeModal(userID database.UserID, room database.ChatRoom) *CodeModal {
     45 	m := &CodeModal{StreamModal{name: name, userID: userID, room: room}}
     46 	m.topics = append(m.topics, m.showTopic(name, userID, room.ID), m.hideTopic(name, userID, room.ID))
     47 	return m
     48 }
     49 
     50 func (m *CodeModal) Css() string {
     51 	return getCss()
     52 }
     53 
     54 func (m *CodeModal) Handle(db *database.DkfDB, authUser database.IUserRenderMessage, topic, csrf string, msgTyp database.ChatMessageType, send func(string)) bool {
     55 	if topic == m.topics[0] {
     56 		send(getCodeModalHTML(m.idx, m.room.Name, csrf, msgTyp, authUser.GetSyntaxHighlightCode()))
     57 		return true
     58 
     59 	} else if topic == m.topics[1] {
     60 		send(`<style>.code-modal-` + strconv.Itoa(m.idx) + `{display:none;}</style>`)
     61 		m.idx++
     62 		return true
     63 	}
     64 
     65 	return false
     66 }
     67 
     68 func getCss() string {
     69 	return strings.Join(strings.Split(`
     70 .code-modal {
     71 	display: block; width: calc(100% - 185px - 100px); height: calc(100% - 50px);
     72 	position: fixed; top: 0; left: calc(50% - ((100% - 185px - 100px)/2) - 92px);
     73 	background-color: gray; z-index: 999; border-radius: 5px;
     74 }
     75     .code-modal .header { position: absolute; top: 0; right: 0; }
     76     .code-modal .header .cancel {
     77 		border: 1px solid gray;
     78 		background-color: #ff7070;
     79 		color: #850000;
     80 		font-size: 18px;
     81 		height: 23px;
     82 		border: 1px solid #850000;
     83 		border-radius: 0 5px 0 5px;
     84 		cursor: pointer;
     85 	}
     86 	.code-modal .header .cancel:hover {
     87 		background-color: #ff6767;
     88 	}
     89     .code-modal .wrapper { position: absolute; top: 25px; left: 10px; right: 10px; bottom: 30px; }
     90     .code-modal .wrapper textarea { width: 100%; height: 100%; color: #fff; background-color: rgba(79,79,79,1); border: 1px solid rgba(90,90,90,1); }
     91     .code-modal .controls { position: absolute; left: 10px; right: 10px; bottom: 5px; }`, "\n"), " ")
     92 }
     93 
     94 func getCodeModalHTML(codeModalIdx int, roomName, csrf string, msgTyp database.ChatMessageType, syntaxHighlightCode string) string {
     95 	htmlTmpl := `<div class="code-modal code-modal-{{ .CodeModalIdx }}">
     96 <form method="post" target="iframe1" action="/api/v1/chat/top-bar/{{ .RoomName }}">
     97 	<input type="hidden" name="csrf" value="{{ .CSRF }}" />
     98 	{{ if .IsMod }}
     99 		<input type="hidden" name="isMod" value="1" />
    100 	{{ end }}
    101 	{{ if .ToUserUsername }}
    102 		<input type="hidden" name="pm" value="{{ .ToUserUsername }}" />
    103 	{{ end }}
    104 	<input type="hidden" name="sender" value="codeModal" />
    105 	<div class="header">
    106 		<button class="cancel" type="submit" name="btn_cancel" value="1">×</button>
    107 	</div>
    108 	<div class=wrapper>
    109 		<textarea name="message" placeholder="Paste your code here..."></textarea>
    110 	</div>
    111 	<div class="controls">
    112 		<button type="submit">send</button>
    113 		<select name="lang">
    114 			{{ range .Langs }}
    115 				<option value="{{ index . 0 }}"{{ if eq $.SyntaxHighlightCode (index . 0) }} selected{{ end }}>{{ index . 1 }}</option>
    116 			{{ end }}
    117 		</select>
    118 	</div>
    119 </form>
    120 </div>`
    121 	data := map[string]any{
    122 		"CSRF":                csrf,
    123 		"RoomName":            roomName,
    124 		"CodeModalIdx":        codeModalIdx,
    125 		"IsMod":               msgTyp.IsMod,
    126 		"ToUserUsername":      msgTyp.ToUserUsername,
    127 		"SyntaxHighlightCode": syntaxHighlightCode,
    128 		"Langs":               langs,
    129 	}
    130 	var buf bytes.Buffer
    131 	_ = utils.Must(template.New("").Parse(htmlTmpl)).Execute(&buf, data)
    132 	return buf.String()
    133 }
    134 
    135 func (_ CodeModal) InterceptMsg(cmd *command.Command) {
    136 	sender := cmd.C.Request().PostFormValue("sender")
    137 	lang := cmd.C.Request().PostFormValue("lang")
    138 	isMod := utils.DoParseBool(cmd.C.Request().PostFormValue("isMod"))
    139 	pm := cmd.C.Request().PostFormValue("pm")
    140 	btnCancel := cmd.C.Request().PostFormValue("btn_cancel")
    141 
    142 	if !cmd.AuthUser.CanUseMultiline || sender != "codeModal" {
    143 		return
    144 	}
    145 
    146 	CodeModal{}.Hide(cmd.AuthUser.ID, cmd.Room.ID)
    147 
    148 	if !isValidLang(lang) {
    149 		lang = ""
    150 	}
    151 	cmd.AuthUser.SetSyntaxHighlightCode(cmd.DB, lang)
    152 
    153 	cmd.ModMsg = isMod
    154 	if pm != "" {
    155 		if err := cmd.SetToUser(database.Username(pm)); err != nil {
    156 			cmd.Err = command.ErrRedirect
    157 			return
    158 		}
    159 		cmd.RedirectQP.Set(command.RedirectPmQP, string(cmd.ToUser.Username))
    160 	}
    161 
    162 	if cmd.OrigMessage == "" || btnCancel == "1" {
    163 		cmd.Err = command.ErrRedirect
    164 		return
    165 	}
    166 
    167 	cmd.OrigMessage = codeFenceWrap(lang, cmd.OrigMessage)
    168 	cmd.Message = codeFenceWrap(lang, cmd.Message)
    169 }
    170 
    171 func codeFenceWrap(lang, msg string) string {
    172 	return "\n```" + lang + "\n" + msg + "\n```\n"
    173 }
    174 
    175 func isValidLang(lang string) (found bool) {
    176 	for _, l := range langs {
    177 		if lang == l[0] {
    178 			return true
    179 		}
    180 	}
    181 	return
    182 }