Capitalization, list model and room header work
- Standardized capitalization for variables and file names everywhere in QML and JS, get rid of mixed camelCase/snakeCase, use camelCase like everywhere in Qt - ListModel items are now stored and returned as real QObjects with PyQt properties and signals. This makes dynamic property binding a lot easier and eliminates the need for many hacks. - New update(), updateOrAppendWhere() methods and roles property for ListModel - RoomHeader now properly updates when the room title or topic changes - Add Backend.pdb(), to make it easier to start the debugger from QML
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 1.4 as Controls1
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
import "side_pane" as SidePane
|
||||
import "sidePane" as SidePane
|
||||
import "chat" as Chat
|
||||
|
||||
//https://doc.qt.io/qt-5/qml-qtquick-controls-splitview.html
|
||||
@@ -14,12 +15,9 @@ Controls1.SplitView {
|
||||
}
|
||||
|
||||
StackView {
|
||||
function show_page(componentName) {
|
||||
pageStack.replace(componentName + ".qml")
|
||||
}
|
||||
function show_room(user_id, room_obj) {
|
||||
function showRoom(userId, roomId) {
|
||||
pageStack.replace(
|
||||
"chat/Root.qml", { user_id: user_id, room: room_obj }
|
||||
"chat/Root.qml", { userId: userId, roomId: roomId }
|
||||
)
|
||||
console.log("replaced")
|
||||
}
|
||||
@@ -28,6 +26,12 @@ Controls1.SplitView {
|
||||
|
||||
onCurrentItemChanged: currentItem.forceActiveFocus()
|
||||
|
||||
initialItem: MouseArea { // TODO: (test, remove)
|
||||
onClicked: pageStack.showRoom(
|
||||
"@test_mary:matrix.org", "!VDSsFIzQnXARSCVNxS:matrix.org"
|
||||
)
|
||||
}
|
||||
|
||||
// Buggy
|
||||
replaceExit: null
|
||||
popExit: null
|
||||
|
@@ -8,7 +8,7 @@ Item {
|
||||
property var imageSource: null
|
||||
property int dimmension: 48
|
||||
|
||||
readonly property string resolved_name:
|
||||
readonly property string resolvedName:
|
||||
! name ? "?" :
|
||||
typeof(name) == "string" ? name :
|
||||
(name.value ? name.value : "?")
|
||||
@@ -21,13 +21,13 @@ Item {
|
||||
id: "letterRectangle"
|
||||
anchors.fill: parent
|
||||
visible: ! invisible && imageSource === null
|
||||
color: resolved_name === "?" ?
|
||||
color: resolvedName === "?" ?
|
||||
Qt.hsla(0, 0, 0.22, 1) :
|
||||
Qt.hsla(Backend.hueFromString(resolved_name), 0.22, 0.5, 1)
|
||||
Qt.hsla(Backend.hueFromString(resolvedName), 0.22, 0.5, 1)
|
||||
|
||||
HLabel {
|
||||
anchors.centerIn: parent
|
||||
text: resolved_name.charAt(0)
|
||||
text: resolvedName.charAt(0)
|
||||
color: "white"
|
||||
font.pixelSize: letterRectangle.height / 1.4
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ ToolButton {
|
||||
onClicked: toolTip.hide()
|
||||
|
||||
ToolTip {
|
||||
id: "toolTip"
|
||||
id: toolTip
|
||||
text: tooltip
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
visible: text ? toolTipZone.containsMouse : false
|
||||
|
@@ -2,11 +2,14 @@ import QtQuick 2.7
|
||||
import QtQuick.Controls 2.0
|
||||
|
||||
HLabel {
|
||||
property string toolTipText: ""
|
||||
|
||||
id: text
|
||||
|
||||
ToolTip {
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
visible: text ? toolTipZone.containsMouse : false
|
||||
text: user_id
|
||||
text: toolTipText
|
||||
}
|
||||
MouseArea {
|
||||
id: toolTipZone
|
||||
|
@@ -2,12 +2,13 @@ import QtQuick 2.7
|
||||
import "../base" as Base
|
||||
|
||||
Base.HLabel {
|
||||
text: date_time.toLocaleDateString()
|
||||
width: messageDelegate.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
topPadding: messageDelegate.isFirstMessage ?
|
||||
0 : messageDelegate.standardSpacing
|
||||
bottomPadding: messageDelegate.standardSpacing
|
||||
|
||||
text: dateTime.toLocaleDateString()
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: normalSize * 1.1
|
||||
color: "darkolivegreen"
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ RowLayout {
|
||||
anchors.right: isOwn ? parent.right : undefined
|
||||
|
||||
readonly property string contentText:
|
||||
isMessage ? "" : ChatJS.get_event_text(type, dict)
|
||||
isMessage ? "" : ChatJS.getEventText(type, dict)
|
||||
|
||||
Base.Avatar {
|
||||
id: avatar
|
||||
@@ -26,7 +26,7 @@ RowLayout {
|
||||
(isUndecryptableEvent ? "darkred" : "gray") + "'>" +
|
||||
(displayName.value || dict.sender) + " " + contentText +
|
||||
" <font size=" + smallSize + "px color='gray'>" +
|
||||
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
Qt.formatDateTime(dateTime, "hh:mm:ss") +
|
||||
"</font></font>"
|
||||
textFormat: Text.RichText
|
||||
background: Rectangle {color: "#DDD"}
|
||||
|
@@ -32,19 +32,13 @@ Row {
|
||||
|
||||
Base.RichLabel {
|
||||
id: contentLabel
|
||||
//text: (isOwn ? "" : content + " ") +
|
||||
//"<font size=" + smallSize + "px color=gray>" +
|
||||
//Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
//"</font>" +
|
||||
// (isOwn ? " " + content : "")
|
||||
//
|
||||
text: (dict.formatted_body ?
|
||||
Backend.htmlFilter.filter(dict.formatted_body) :
|
||||
dict.body) +
|
||||
" <font size=" + smallSize + "px color=gray>" +
|
||||
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
Qt.formatDateTime(dateTime, "hh:mm:ss") +
|
||||
"</font>" +
|
||||
(is_local_echo ?
|
||||
(isLocalEcho ?
|
||||
" <font size=" + smallSize + "px>⏳</font>" : "")
|
||||
textFormat: Text.RichText
|
||||
background: Rectangle {color: "#DDD"}
|
||||
|
@@ -7,22 +7,22 @@ import "utils.js" as ChatJS
|
||||
Column {
|
||||
id: "messageDelegate"
|
||||
|
||||
function mins_between(date1, date2) {
|
||||
function minsBetween(date1, date2) {
|
||||
return Math.round((((date2 - date1) % 86400000) % 3600000) / 60000)
|
||||
}
|
||||
|
||||
function is_message(type_) { return type_.startsWith("RoomMessage") }
|
||||
function getIsMessage(type_) { return type_.startsWith("RoomMessage") }
|
||||
|
||||
function get_previous_item() {
|
||||
function getPreviousItem() {
|
||||
return index < messageListView.model.count - 1 ?
|
||||
messageListView.model.get(index + 1) : null
|
||||
}
|
||||
|
||||
property var previousItem: get_previous_item()
|
||||
property var previousItem: getPreviousItem()
|
||||
signal reloadPreviousItem()
|
||||
onReloadPreviousItem: previousItem = get_previous_item()
|
||||
onReloadPreviousItem: previousItem = getPreviousItem()
|
||||
|
||||
readonly property bool isMessage: is_message(type)
|
||||
readonly property bool isMessage: getIsMessage(type)
|
||||
|
||||
readonly property bool isUndecryptableEvent:
|
||||
type === "OlmEvent" || type === "MegolmEvent"
|
||||
@@ -31,7 +31,7 @@ Column {
|
||||
Backend.getUserDisplayName(dict.sender)
|
||||
|
||||
readonly property bool isOwn:
|
||||
chatPage.user_id === dict.sender
|
||||
chatPage.userId === dict.sender
|
||||
|
||||
readonly property bool isFirstEvent: type == "RoomCreateEvent"
|
||||
|
||||
@@ -39,19 +39,19 @@ Column {
|
||||
previousItem &&
|
||||
! talkBreak &&
|
||||
! dayBreak &&
|
||||
is_message(previousItem.type) === isMessage &&
|
||||
getIsMessage(previousItem.type) === isMessage &&
|
||||
previousItem.dict.sender === dict.sender &&
|
||||
mins_between(previousItem.date_time, date_time) <= 5
|
||||
minsBetween(previousItem.dateTime, dateTime) <= 5
|
||||
|
||||
readonly property bool dayBreak:
|
||||
isFirstEvent ||
|
||||
previousItem &&
|
||||
date_time.getDay() != previousItem.date_time.getDay()
|
||||
dateTime.getDay() != previousItem.dateTime.getDay()
|
||||
|
||||
readonly property bool talkBreak:
|
||||
previousItem &&
|
||||
! dayBreak &&
|
||||
mins_between(previousItem.date_time, date_time) >= 20
|
||||
minsBetween(previousItem.dateTime, dateTime) >= 20
|
||||
|
||||
|
||||
property int standardSpacing: 16
|
||||
@@ -59,8 +59,8 @@ Column {
|
||||
property int verticalPadding: 5
|
||||
|
||||
ListView.onAdd: {
|
||||
var next_delegate = messageListView.contentItem.children[index]
|
||||
if (next_delegate) { next_delegate.reloadPreviousItem() }
|
||||
var nextDelegate = messageListView.contentItem.children[index]
|
||||
if (nextDelegate) { nextDelegate.reloadPreviousItem() }
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
|
@@ -14,8 +14,7 @@ Rectangle {
|
||||
id: messageListView
|
||||
anchors.fill: parent
|
||||
delegate: MessageDelegate {}
|
||||
model: Backend.models.roomEvents.get(chatPage.room.room_id)
|
||||
//highlight: Rectangle {color: "lightsteelblue"; radius: 5}
|
||||
model: Backend.models.roomEvents.get(chatPage.roomId)
|
||||
|
||||
clip: true
|
||||
topMargin: space
|
||||
@@ -31,7 +30,7 @@ Rectangle {
|
||||
|
||||
onYPosChanged: {
|
||||
if (yPos <= 0.1) {
|
||||
Backend.loadPastEvents(chatPage.room.room_id)
|
||||
Backend.loadPastEvents(chatPage.roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,10 @@ import QtQuick.Layouts 1.4
|
||||
import "../base" as Base
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property string displayName: ""
|
||||
property string topic: ""
|
||||
|
||||
id: "root"
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 36
|
||||
Layout.maximumHeight: Layout.minimumHeight
|
||||
@@ -19,21 +22,23 @@ Rectangle {
|
||||
id: "avatar"
|
||||
Layout.alignment: Qt.AlignTop
|
||||
dimmension: root.Layout.minimumHeight
|
||||
name: chatPage.room.display_name
|
||||
name: displayName
|
||||
}
|
||||
|
||||
Base.HLabel {
|
||||
id: "roomName"
|
||||
text: chatPage.room.display_name
|
||||
text: displayName
|
||||
font.pixelSize: bigSize
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
Layout.maximumWidth: row.width - row.spacing * (row.children.length - 1) - avatar.width
|
||||
Layout.maximumWidth:
|
||||
row.width - row.spacing * (row.children.length - 1) -
|
||||
avatar.width
|
||||
}
|
||||
|
||||
Base.HLabel {
|
||||
id: "roomDescription"
|
||||
text: chatPage.room.description || ""
|
||||
id: "roomTopic"
|
||||
text: topic
|
||||
font.pixelSize: smallSize
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
|
@@ -3,16 +3,23 @@ import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
ColumnLayout {
|
||||
property var user_id: null
|
||||
property var room: null
|
||||
property var userId: null
|
||||
property var roomId: null
|
||||
|
||||
property var roomInfo:
|
||||
Backend.models.rooms.get(userId).getWhere("roomId", roomId)
|
||||
|
||||
id: chatPage
|
||||
id: "chatPage"
|
||||
spacing: 0
|
||||
onFocusChanged: sendBox.setFocus()
|
||||
|
||||
RoomHeader {}
|
||||
RoomHeader {
|
||||
id: "roomHeader"
|
||||
displayName: roomInfo.displayName
|
||||
topic: roomInfo.topic
|
||||
}
|
||||
|
||||
MessageList {}
|
||||
TypingUsersBar {}
|
||||
SendBox { id: sendBox }
|
||||
SendBox { id: "sendBox" }
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ Rectangle {
|
||||
|
||||
Base.Avatar {
|
||||
id: "avatar"
|
||||
name: Backend.getUserDisplayName(chatPage.user_id)
|
||||
name: Backend.getUserDisplayName(chatPage.userId)
|
||||
dimmension: root.Layout.minimumHeight
|
||||
//visible: textArea.text === ""
|
||||
visible: textArea.height <= root.Layout.minimumHeight
|
||||
@@ -43,13 +43,13 @@ Rectangle {
|
||||
font.pixelSize: 16
|
||||
focus: true
|
||||
|
||||
function set_typing(typing) {
|
||||
Backend.clientManager.clients[chatPage.user_id]
|
||||
.setTypingState(chatPage.room.room_id, typing)
|
||||
function setTyping(typing) {
|
||||
Backend.clientManager.clients[chatPage.userId]
|
||||
.setTypingState(chatPage.roomId, typing)
|
||||
}
|
||||
|
||||
onTypedTextChanged: set_typing(Boolean(text))
|
||||
onEditingFinished: set_typing(false) // when lost focus
|
||||
onTypedTextChanged: setTyping(Boolean(text))
|
||||
onEditingFinished: setTyping(false) // when lost focus
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
event.accepted = true
|
||||
@@ -62,8 +62,8 @@ Rectangle {
|
||||
}
|
||||
|
||||
if (textArea.text === "") { return }
|
||||
Backend.clientManager.clients[chatPage.user_id]
|
||||
.sendMarkdown(chatPage.room.room_id, textArea.text)
|
||||
Backend.clientManager.clients[chatPage.userId]
|
||||
.sendMarkdown(chatPage.roomId, textArea.text)
|
||||
textArea.clear()
|
||||
}
|
||||
|
||||
|
@@ -11,19 +11,12 @@ Rectangle {
|
||||
Layout.maximumHeight: Layout.minimumHeight
|
||||
color: "#BBB"
|
||||
|
||||
property var typingUsers: chatPage.roomInfo.typingUsers
|
||||
|
||||
Base.HLabel {
|
||||
id: "usersLabel"
|
||||
anchors.fill: parent
|
||||
|
||||
Timer {
|
||||
interval: 500
|
||||
repeat: true
|
||||
running: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: usersLabel.text = ChatJS.get_typing_users_text(
|
||||
chatPage.user_id, chatPage.room.room_id
|
||||
)
|
||||
}
|
||||
text: ChatJS.getTypingUsersText(typingUsers, chatPage.userId)
|
||||
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 1
|
||||
|
@@ -1,4 +1,4 @@
|
||||
function get_event_text(type, dict) {
|
||||
function getEventText(type, dict) {
|
||||
switch (type) {
|
||||
case "RoomCreateEvent":
|
||||
return (dict.federate ? "allowed" : "blocked") +
|
||||
@@ -18,14 +18,14 @@ function get_event_text(type, dict) {
|
||||
break
|
||||
|
||||
case "RoomHistoryVisibilityEvent":
|
||||
return get_history_visibility_event_text(dict)
|
||||
return getHistoryVisibilityEventText(dict)
|
||||
break
|
||||
|
||||
case "PowerLevelsEvent":
|
||||
return "changed the room's permissions."
|
||||
|
||||
case "RoomMemberEvent":
|
||||
return get_member_event_text(dict)
|
||||
return getMemberEventText(dict)
|
||||
break
|
||||
|
||||
case "RoomAliasEvent":
|
||||
@@ -58,7 +58,7 @@ function get_event_text(type, dict) {
|
||||
}
|
||||
|
||||
|
||||
function get_history_visibility_event_text(dict) {
|
||||
function getHistoryVisibilityEventText(dict) {
|
||||
switch (dict.history_visibility) {
|
||||
case "shared":
|
||||
var end = "all room members."
|
||||
@@ -81,7 +81,7 @@ function get_history_visibility_event_text(dict) {
|
||||
}
|
||||
|
||||
|
||||
function get_member_event_text(dict) {
|
||||
function getMemberEventText(dict) {
|
||||
var info = dict.content, prev = dict.prev_content
|
||||
|
||||
if (! prev || (info.membership != prev.membership)) {
|
||||
@@ -127,15 +127,12 @@ function get_member_event_text(dict) {
|
||||
}
|
||||
|
||||
|
||||
function get_typing_users_text(account_id, room_id) {
|
||||
function getTypingUsersText(users, ourAccountId) {
|
||||
var names = []
|
||||
var room = Backend.models.rooms.get(account_id)
|
||||
.getWhere("room_id", room_id)
|
||||
|
||||
for (var i = 0; i < room.typing_users.length; i++) {
|
||||
if (room.typing_users[i] !== account_id) {
|
||||
names.push(Backend.getUserDisplayName(room.typing_users[i], false)
|
||||
.result())
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
if (users[i] !== ourAccountId) {
|
||||
names.push(Backend.getUserDisplayName(users[i], false).result())
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,9 +0,0 @@
|
||||
import QtQuick 2.7
|
||||
import "../base" as Base
|
||||
|
||||
Rectangle {
|
||||
Base.HLabel {
|
||||
anchors.centerIn: parent
|
||||
text: "Home page"
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ ColumnLayout {
|
||||
id: "row"
|
||||
spacing: 0
|
||||
|
||||
Base.Avatar { id: "avatar"; name: display_name; dimmension: 36 }
|
||||
Base.Avatar { id: "avatar"; name: displayName; dimmension: 36 }
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
@@ -21,7 +21,7 @@ ColumnLayout {
|
||||
|
||||
Base.HLabel {
|
||||
id: "accountLabel"
|
||||
text: display_name.value || user_id
|
||||
text: displayName.value || userId
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
Layout.fillWidth: true
|
||||
@@ -31,7 +31,7 @@ ColumnLayout {
|
||||
|
||||
TextField {
|
||||
id: "statusEdit"
|
||||
text: status_message || ""
|
||||
text: statusMessage || ""
|
||||
placeholderText: qsTr("Set status message")
|
||||
background: null
|
||||
color: "black"
|
||||
@@ -44,7 +44,7 @@ ColumnLayout {
|
||||
rightPadding: leftPadding
|
||||
|
||||
onEditingFinished: {
|
||||
Backend.setStatusMessage(user_id, text)
|
||||
Backend.setStatusMessage(userId, text)
|
||||
pageStack.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ ColumnLayout {
|
||||
id: "roomList"
|
||||
visible: true
|
||||
interactive: false // no scrolling
|
||||
for_user_id: user_id
|
||||
forUserId: userId
|
||||
|
||||
Layout.minimumHeight:
|
||||
roomList.visible ?
|
@@ -9,24 +9,21 @@ MouseArea {
|
||||
width: roomList.width
|
||||
height: roomList.childrenHeight
|
||||
|
||||
onClicked: pageStack.show_room(
|
||||
roomList.for_user_id,
|
||||
roomList.model.get(index)
|
||||
)
|
||||
onClicked: pageStack.showRoom(roomList.forUserId, roomId)
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
id: row
|
||||
spacing: 1
|
||||
|
||||
Base.Avatar { id: avatar; name: display_name; dimmension: root.height }
|
||||
Base.Avatar { id: avatar; name: displayName; dimmension: root.height }
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
Base.HLabel {
|
||||
id: roomLabel
|
||||
text: display_name ? display_name : "<i>Empty room</i>"
|
||||
text: displayName ? displayName : "<i>Empty room</i>"
|
||||
textFormat: Text.StyledText
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
@@ -39,18 +36,18 @@ MouseArea {
|
||||
rightPadding: leftPadding
|
||||
}
|
||||
Base.HLabel {
|
||||
function get_text() {
|
||||
return SidePaneJS.get_last_room_event_text(room_id)
|
||||
function getText() {
|
||||
return SidePaneJS.getLastRoomEventText(roomId)
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Backend.models.roomEvents.get(room_id)
|
||||
onChanged: subtitleLabel.text = subtitleLabel.get_text()
|
||||
target: Backend.models.roomEvents.get(roomId)
|
||||
onChanged: subtitleLabel.text = subtitleLabel.getText()
|
||||
}
|
||||
|
||||
id: subtitleLabel
|
||||
visible: text !== ""
|
||||
text: get_text()
|
||||
text: getText()
|
||||
textFormat: Text.StyledText
|
||||
|
||||
font.pixelSize: smallSize
|
@@ -4,7 +4,7 @@ import QtQuick.Layouts 1.4
|
||||
import "../base" as Base
|
||||
|
||||
ListView {
|
||||
property var for_user_id: null
|
||||
property var forUserId: null
|
||||
|
||||
property int childrenHeight: 36
|
||||
property int contentHeight: 0
|
||||
@@ -16,6 +16,6 @@ ListView {
|
||||
|
||||
id: "roomList"
|
||||
spacing: 8
|
||||
model: Backend.models.rooms.get(for_user_id)
|
||||
model: Backend.models.rooms.get(forUserId)
|
||||
delegate: RoomDelegate {}
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
.import "../chat/utils.js" as ChatJS
|
||||
|
||||
|
||||
function get_last_room_event_text(room_id) {
|
||||
var eventsModel = Backend.models.roomEvents.get(room_id)
|
||||
function getLastRoomEventText(roomId) {
|
||||
var eventsModel = Backend.models.roomEvents.get(roomId)
|
||||
|
||||
for (var i = 0; i < eventsModel.count; i++) {
|
||||
var ev = eventsModel.get(i)
|
||||
@@ -19,7 +19,7 @@ function get_last_room_event_text(room_id) {
|
||||
var undecryptable = ev.type === "OlmEvent" || ev.type === "MegolmEvent"
|
||||
|
||||
if (undecryptable || ev.type.startsWith("RoomMessage")) {
|
||||
var color = ev.dict.sender === roomList.for_user_id ?
|
||||
var color = ev.dict.sender === roomList.forUserId ?
|
||||
"darkblue" : "purple"
|
||||
|
||||
return "<font color='" +
|
||||
@@ -36,7 +36,7 @@ function get_last_room_event_text(room_id) {
|
||||
"'>" +
|
||||
name +
|
||||
" " +
|
||||
ChatJS.get_event_text(ev.type, ev.dict) +
|
||||
ChatJS.getEventText(ev.type, ev.dict) +
|
||||
"</font>"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user