-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrender-message.js
170 lines (137 loc) · 4.15 KB
/
render-message.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import { createRenderer } from "./markdown.js"
import { insertAtCursor } from "./ui-utils.js"
const md = createRenderer()
const mdHtml = createRenderer({ html: true })
const RenderModes = Object.freeze({
default: "default",
allowHTML: "allowHTML",
onlyHTML: "onlyHTML",
plainText: "plainText",
})
/**
* @typedef RenderMode
* @type {RenderModes[keyof RenderModes]}
*/
/**
* @param {string} markup
* @param {object} options
* @param {RenderMode} options.mode
*/
const renderMarkdown = (markup, { mode = RenderModes.default } = {}) => {
if (mode === RenderModes.default) {
return md.render(markup)
} else if (mode === RenderModes.allowHTML) {
return mdHtml.render(markup)
} else if (mode === RenderModes.onlyHTML) {
return markup
} else if (mode === RenderModes.plainText) {
return markup
}
}
/**
* @param {Msg} args
* @param {object} options
* @param {RenderMode} options.renderMode
*/
const renderMessage = (args, { renderMode = RenderModes.default } = {}) => {
// Message container
const messageEl = document.createElement('div')
messageEl.classList.add('message')
if (args.nick === myNick) {
messageEl.classList.add('me')
} else if (args.nick === '!') {
messageEl.classList.add('warn')
} else if (args.nick === '*') {
messageEl.classList.add('info')
} else if (args.admin) {
messageEl.classList.add('admin')
} else if (args.mod) {
messageEl.classList.add('mod')
}
// Nickname
const nickSpanEl = document.createElement('span')
nickSpanEl.classList.add('nick', 'chat-nick')
messageEl.appendChild(nickSpanEl)
if (args.trip) {
const tripEl = document.createElement('span')
tripEl.textContent = args.trip + ' '
tripEl.classList.add('trip')
nickSpanEl.appendChild(tripEl)
}
if (args.nick) {
const nickLinkEl = document.createElement('a')
nickLinkEl.textContent = args.nick
const date = new Date(args.time || Date.now())
nickLinkEl.title = date.toLocaleString()
nickSpanEl.appendChild(nickLinkEl)
if (args.color && /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(args.color)) {
nickLinkEl.style.color = `#${args.color}`
} else if (args.nick === 'jeb_') {
nickLinkEl.classList.add('jebbed')
}
nickLinkEl.addEventListener('click', () => {
// Reply to a whisper or info is meaningless
if (args.type === 'whisper' || args.nick === '*' || args.nick === '!') {
insertAtCursor(args.text)
} else {
insertAtCursor(`@${args.nick} `)
}
input.focus()
})
nickLinkEl.addEventListener('contextmenu', (e) => {
e.preventDefault()
let replyText = ''
let isOverLong = false
// Cut overlong text
if (args.text.length > 350) {
replyText = args.text.slice(0, 350)
isOverLong = true
}
// Add nickname
if (args.trip) {
replyText = '>' + args.trip + ' ' + args.nick + ':\n'
} else {
replyText = '>' + args.nick + ':\n'
}
// Split text by line
let lines = args.text.split('\n')
// Cut overlong lines
if (lines.length >= 8) {
lines = lines.slice(0, 8)
isOverLong = true
}
for (let replyLine of lines) {
// Cut third replied text
if (!replyLine.startsWith('>>')) {
replyText += '>' + replyLine + '\n'
}
}
// Add elipsis if text is cutted
if (isOverLong) {
replyText += '>……\n'
}
replyText += '\n'
// Add mention when reply to others
if (args.nick != myNickName() && args.type != 'whisper' && args.nick != '*' && args.nick != '!') {
replyText += `@${args.nick} `
}
// Insert reply text
replyText += input.value
input.value = ''
insertAtCursor(replyText)
input.focus()
})
}
// Text
const textEl = document.createElement('p')
textEl.classList.add('text')
let rendered = renderMarkdown(args.text, { mode: renderMode })
if (renderMode === RenderModes.plainText) {
textEl.textContent = rendered
} else {
textEl.innerHTML = rendered
}
messageEl.appendChild(textEl)
return messageEl
}
export { RenderModes, renderMarkdown, renderMessage }