mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-14 11:05:47 +05:00
* fix checkout alignmnet * fixed create identity issue * added logic for edit identity as well as create identity * final changes * UX changes * minor fixes * Signed Create identity is working now * minor changes * friend node profile pic is aligned now * People->Edit && create identity popup responsive * updated & refactor code * changes added * Update people_ownids.js * Update people_util.js * feat: people Web page UI * minor-fix * fix prettier & eslint issue * updated changes * updated changes * minor fix * update changes
525 lines
15 KiB
JavaScript
525 lines
15 KiB
JavaScript
const m = require('mithril');
|
|
const rs = require('rswebui');
|
|
const peopleUtil = require('people/people_util');
|
|
|
|
// **************** utility functions ********************
|
|
|
|
function loadLobbyDetails(id, apply) {
|
|
rs.rsJsonApiRequest(
|
|
'/rsMsgs/getChatLobbyInfo',
|
|
{
|
|
id,
|
|
},
|
|
(detail) => {
|
|
if (detail.retval) {
|
|
apply(detail.info);
|
|
}
|
|
},
|
|
true,
|
|
{},
|
|
undefined,
|
|
// Custom serializer NOTE:
|
|
// Since id represents 64-bit int(see deserializer note below)
|
|
// Instead of using JSON.stringify, this function directly
|
|
// creates a json string manually.
|
|
() => '{"id":' + id + '}'
|
|
);
|
|
}
|
|
|
|
function sortLobbies(lobbies) {
|
|
if (lobbies !== undefined) {
|
|
const list = [...lobbies];
|
|
list.sort((a, b) => a.lobby_name.localeCompare(b.lobby_name));
|
|
return list;
|
|
}
|
|
// return lobbies; // fallback on reload page in browser, keep undefiend
|
|
}
|
|
|
|
// ***************************** models ***********************************
|
|
|
|
const ChatRoomsModel = {
|
|
allRooms: [],
|
|
knownSubscrIds: [], // to exclude subscribed from public rooms (subscribedRooms filled to late)
|
|
subscribedRooms: {},
|
|
loadPublicRooms() {
|
|
// TODO: this doesn't preserve id of rooms,
|
|
// use regex on response to extract ids.
|
|
rs.rsJsonApiRequest(
|
|
'/rsMsgs/getListOfNearbyChatLobbies',
|
|
{},
|
|
(data) => (ChatRoomsModel.allRooms = sortLobbies(data.public_lobbies))
|
|
);
|
|
},
|
|
loadSubscribedRooms(after = null) {
|
|
// ChatRoomsModel.subscribedRooms = {};
|
|
rs.rsJsonApiRequest(
|
|
'/rsMsgs/getChatLobbyList',
|
|
{},
|
|
// JS uses double precision numbers of 64 bit. It is equivalent
|
|
// to 53 bits of precision. All large precision ints will
|
|
// get truncated to an approximation.
|
|
// This API uses Cpp-style 64 bits for `id`.
|
|
// So we use the string-value 'xstr64' instead
|
|
(data) => {
|
|
const ids = data.cl_list.map((lid) => lid.xstr64);
|
|
ChatRoomsModel.knownSubscrIds = ids;
|
|
const rooms = {};
|
|
ids.map((id) =>
|
|
loadLobbyDetails(id, (info) => {
|
|
rooms[id] = info;
|
|
if (Object.keys(rooms).length === ids.length) {
|
|
// apply rooms to subscribedRooms only after reading all room-details, so sorting all or nothing
|
|
ChatRoomsModel.subscribedRooms = rooms;
|
|
}
|
|
})
|
|
);
|
|
if (after != null) {
|
|
after();
|
|
}
|
|
}
|
|
);
|
|
},
|
|
subscribed(info) {
|
|
return this.knownSubscrIds.includes(info.lobby_id.xstr64);
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Message displays a single Chat-Message<br>
|
|
* currently removes formatting and in consequence inline links
|
|
* msg: Message to Display
|
|
*/
|
|
const Message = () => {
|
|
let msg = null; // message to display
|
|
let text = ''; // extracted text to display
|
|
let datetime = ''; // date time to display
|
|
let username = ''; // username to display (later may be linked)
|
|
return {
|
|
oninit: (vnode) => {
|
|
console.info('chat Message', vnode);
|
|
msg = vnode.attrs;
|
|
datetime = new Date(msg.sendTime * 1000).toLocaleTimeString();
|
|
username = rs.userList.username(msg.lobby_peer_gxs_id);
|
|
text = msg.msg
|
|
.replaceAll('<br/>', '\n')
|
|
.replace(new RegExp('<style[^<]*</style>|<[^>]*>', 'gm'), '');
|
|
console.info('chat Text', text);
|
|
},
|
|
view: () =>
|
|
m(
|
|
'.message',
|
|
m('span.datetime', datetime),
|
|
m('span.username', username),
|
|
m('span.messagetext', text)
|
|
),
|
|
};
|
|
};
|
|
|
|
const ChatLobbyModel = {
|
|
currentLobby: {
|
|
lobby_name: '...',
|
|
},
|
|
lobby_user: '...',
|
|
isSubscribed: false,
|
|
messages: [],
|
|
users: [],
|
|
setupAction: (lobbyId, nick) => {},
|
|
setIdentity(lobbyId, nick) {
|
|
rs.rsJsonApiRequest(
|
|
'/rsMsgs/setIdentityForChatLobby',
|
|
{},
|
|
() => m.route.set('/chat/:lobby_id', { lobbyId }),
|
|
true,
|
|
{},
|
|
JSON.parse,
|
|
() => '{"lobby_id":' + lobbyId + ',"nick":"' + nick + '"}'
|
|
);
|
|
},
|
|
enterPublicLobby(lobbyId, nick) {
|
|
console.info('joinVisibleChatLobby', nick, '@', lobbyId);
|
|
rs.rsJsonApiRequest(
|
|
'/rsMsgs/joinVisibleChatLobby',
|
|
{},
|
|
() => {
|
|
loadLobbyDetails(lobbyId, (info) => {
|
|
ChatRoomsModel.subscribedRooms[lobbyId] = info;
|
|
ChatRoomsModel.loadSubscribedRooms(() => {
|
|
m.route.set('/chat/:lobby', { lobby: info.lobby_id.xstr64 });
|
|
});
|
|
});
|
|
},
|
|
true,
|
|
{},
|
|
JSON.parse,
|
|
() => '{"lobby_id":' + lobbyId + ',"own_id":"' + nick + '"}'
|
|
);
|
|
},
|
|
unsubscribeChatLobby(lobbyId, follow) {
|
|
console.info('unsubscribe lobby', lobbyId);
|
|
rs.rsJsonApiRequest(
|
|
'/rsMsgs/unsubscribeChatLobby',
|
|
{},
|
|
() => ChatRoomsModel.loadSubscribedRooms(follow),
|
|
true,
|
|
{},
|
|
JSON.parse,
|
|
() => '{"lobby_id":' + lobbyId + '}'
|
|
);
|
|
},
|
|
chatId(action) {
|
|
return { type: 3, lobby_id: { xstr64: m.route.param('lobby') } };
|
|
},
|
|
loadLobby(currentlobbyid) {
|
|
loadLobbyDetails(currentlobbyid, (detail) => {
|
|
this.setupAction = this.setIdentity;
|
|
this.currentLobby = detail;
|
|
this.isSubscribed = true;
|
|
this.lobby_user = rs.userList.username(detail.gxs_id) || '???';
|
|
const lobbyid = currentlobbyid;
|
|
// apply existing messages to current lobby view
|
|
rs.events[15].chatMessages(
|
|
this.chatId(),
|
|
rs.events[15],
|
|
(l) => (this.messages = l.map((msg) => m(Message, msg)))
|
|
);
|
|
// register for chatEvents for future messages
|
|
rs.events[15].notify = (chatMessage) => {
|
|
if (chatMessage.chat_id.type === 3 && chatMessage.chat_id.lobby_id.xstr64 === lobbyid) {
|
|
this.messages.push(m(Message, chatMessage));
|
|
m.redraw();
|
|
}
|
|
};
|
|
// lookup for chat-user names (only snapshot, we don't get notified about changes of participants)
|
|
const names = detail.gxs_ids.reduce((a, u) => a.concat(rs.userList.username(u.key)), []);
|
|
names.sort((a, b) => a.localeCompare(b));
|
|
this.users = [];
|
|
names.forEach((name) => (this.users = this.users.concat([m('.user', name)])));
|
|
return this.users;
|
|
});
|
|
},
|
|
loadPublicLobby(currentlobbyid) {
|
|
console.info('loadPublicLobby ChatRoomsModel:', ChatRoomsModel);
|
|
this.setupAction = this.enterPublicLobby;
|
|
this.isSubscribed = false;
|
|
ChatRoomsModel.allRooms.forEach((it) => {
|
|
if (it.lobby_id.xstr64 === currentlobbyid) {
|
|
this.currentLobby = it;
|
|
this.lobby_user = '???';
|
|
this.lobbyid = currentlobbyid;
|
|
}
|
|
});
|
|
this.users = [];
|
|
},
|
|
sendMessage(msg, onsuccess) {
|
|
rs.rsJsonApiRequest(
|
|
'/rsmsgs/sendChat',
|
|
{},
|
|
() => {
|
|
// adding own message to log
|
|
rs.events[15].handler(
|
|
{
|
|
mChatMessage: {
|
|
chat_id: this.chatId(),
|
|
msg,
|
|
sendTime: new Date().getTime() / 1000,
|
|
lobby_peer_gxs_id: this.currentLobby.gxs_id,
|
|
},
|
|
},
|
|
rs.events[15]
|
|
);
|
|
onsuccess();
|
|
},
|
|
true,
|
|
{},
|
|
undefined,
|
|
() =>
|
|
'{"id":{"type": 3,"lobby_id":' +
|
|
m.route.param('lobby') +
|
|
'}, "msg":' +
|
|
JSON.stringify(msg) +
|
|
'}'
|
|
);
|
|
},
|
|
selected(info, selName, defaultName) {
|
|
const currid = (ChatLobbyModel.currentLobby.lobby_id || { xstr64: m.route.param('lobby') })
|
|
.xstr64;
|
|
return (info.lobby_id.xstr64 === currid ? selName : '') + defaultName;
|
|
},
|
|
switchToEvent(info) {
|
|
return () => {
|
|
ChatLobbyModel.currentLobby = info;
|
|
m.route.set('/chat/:lobby', { lobby: info.lobby_id.xstr64 });
|
|
ChatLobbyModel.loadLobby(info.lobby_id.xstr64); // update
|
|
};
|
|
},
|
|
setupEvent(info) {
|
|
return () => {
|
|
m.route.set('/chat/:lobby/setup', { lobby: info.lobby_id.xstr64 });
|
|
ChatLobbyModel.loadPublicLobby(info.lobby_id.xstr64); // update
|
|
};
|
|
},
|
|
};
|
|
|
|
// ************************* views ****************************
|
|
|
|
const Lobby = () => {
|
|
let info = {};
|
|
let tagname = '';
|
|
let onclick = (e) => {};
|
|
let lobbytagname = '';
|
|
return {
|
|
oninit: (v) => {
|
|
info = v.attrs.info;
|
|
tagname = v.attrs.tagname;
|
|
onclick = v.attrs.onclick || ((e) => {});
|
|
lobbytagname = v.attrs.lobbytagname || 'mainname';
|
|
},
|
|
view: (v) => {
|
|
return m(
|
|
ChatLobbyModel.selected(info, '.selected-lobby', tagname),
|
|
{
|
|
key: info.lobby_id.xstr64,
|
|
|
|
onclick,
|
|
},
|
|
[
|
|
m('h5', { class: lobbytagname }, info.lobby_name === '' ? '<unnamed>' : info.lobby_name),
|
|
m('.topic', info.lobby_topic),
|
|
]
|
|
);
|
|
},
|
|
};
|
|
};
|
|
|
|
const LobbyList = {
|
|
view(vnode) {
|
|
const tagname = vnode.attrs.tagname;
|
|
const lobbytagname = vnode.attrs.lobbytagname;
|
|
const onclick = vnode.attrs.onclick || (() => null);
|
|
return [
|
|
m('hr'),
|
|
vnode.attrs.rooms.map((info) =>
|
|
m(Lobby, {
|
|
info,
|
|
tagname,
|
|
lobbytagname,
|
|
onclick: onclick(info),
|
|
})
|
|
),
|
|
];
|
|
},
|
|
};
|
|
|
|
const SubscribedLeftLobbies = {
|
|
view() {
|
|
return [
|
|
m('h5.lefttitle', 'subscribed:'),
|
|
m(LobbyList, {
|
|
rooms: sortLobbies(Object.values(ChatRoomsModel.subscribedRooms)),
|
|
tagname: '.leftlobby.subscribed',
|
|
lobbytagname: 'leftname',
|
|
onclick: ChatLobbyModel.switchToEvent,
|
|
}),
|
|
];
|
|
},
|
|
};
|
|
|
|
const SubscribedLobbies = {
|
|
view() {
|
|
return m('.widget', [
|
|
m('h3', 'Subscribed chat rooms'),
|
|
m(LobbyList, {
|
|
rooms: sortLobbies(Object.values(ChatRoomsModel.subscribedRooms)),
|
|
tagname: '.lobby.subscribed',
|
|
onclick: ChatLobbyModel.switchToEvent,
|
|
}),
|
|
]);
|
|
},
|
|
};
|
|
|
|
const PublicLeftLobbies = {
|
|
view() {
|
|
return [
|
|
m('h5.lefttitle', 'public:'),
|
|
m(LobbyList, {
|
|
rooms: Object.values(ChatRoomsModel.allRooms).filter(
|
|
(info) => !ChatRoomsModel.subscribed(info)
|
|
),
|
|
tagname: '.leftlobby.public',
|
|
lobbytagname: 'leftname',
|
|
onclick: ChatLobbyModel.setupEvent,
|
|
}),
|
|
];
|
|
},
|
|
};
|
|
|
|
const PublicLobbies = () => {
|
|
return m('.widget', [
|
|
m('h3', 'Public chat rooms'),
|
|
m(LobbyList, {
|
|
rooms: ChatRoomsModel.allRooms.filter((info) => !ChatRoomsModel.subscribed(info)),
|
|
tagname: '.lobby.public',
|
|
onclick: ChatLobbyModel.setupEvent,
|
|
}),
|
|
]);
|
|
};
|
|
|
|
const LobbyName = () => {
|
|
return m(
|
|
'h3.lobbyName',
|
|
ChatLobbyModel.isSubscribed
|
|
? [m('span.chatusername', ChatLobbyModel.lobby_user), m('span.chatatchar', '@')]
|
|
: [],
|
|
m('span.chatlobbyname', ChatLobbyModel.currentLobby.lobby_name),
|
|
m.route.param('subaction') !== 'setup'
|
|
? [
|
|
m('i.fas.fa-cog.setupicon', {
|
|
title: 'configure lobby',
|
|
onclick: () =>
|
|
m.route.set(
|
|
'/chat/:lobby/:subaction',
|
|
{
|
|
lobby: m.route.param('lobby'),
|
|
subaction: 'setup',
|
|
},
|
|
{ replace: true }
|
|
),
|
|
}),
|
|
]
|
|
: [],
|
|
ChatLobbyModel.isSubscribed
|
|
? [
|
|
m('i.fas.fa-sign-out-alt.leaveicon', {
|
|
title: 'leaving lobby',
|
|
onclick: () =>
|
|
ChatLobbyModel.unsubscribeChatLobby(m.route.param('lobby'), () => {
|
|
m.route.set('/chat', null, { replace: true });
|
|
}),
|
|
}),
|
|
]
|
|
: []
|
|
);
|
|
};
|
|
|
|
// ***************************** Page Layouts ******************************
|
|
|
|
const Layout = () => {
|
|
return {
|
|
view: () => m('.tab-page', [m(SubscribedLobbies), PublicLobbies()]),
|
|
};
|
|
};
|
|
|
|
const LayoutSingle = () => {
|
|
return {
|
|
oninit: () => ChatLobbyModel.loadLobby(m.route.param('lobby')),
|
|
view: (vnode) =>
|
|
m('.tab-page', [
|
|
LobbyName(),
|
|
m('.lobbies', m(SubscribedLeftLobbies), m(PublicLeftLobbies)),
|
|
m('.messages', ChatLobbyModel.messages),
|
|
m('.rightbar', ChatLobbyModel.users),
|
|
m(
|
|
'.chatMessage',
|
|
{},
|
|
m('textarea.chatMsg', {
|
|
placeholder: 'enter new message and press return to send',
|
|
onkeydown: (e) => {
|
|
if (e.code === 'Enter') {
|
|
const msg = e.target.value;
|
|
e.target.value = ' sending ... ';
|
|
ChatLobbyModel.sendMessage(msg, () => (e.target.value = ''));
|
|
return false;
|
|
}
|
|
},
|
|
})
|
|
),
|
|
]),
|
|
};
|
|
};
|
|
|
|
const LayoutSetup = () => {
|
|
let ownIds = [];
|
|
return {
|
|
oninit: () => peopleUtil.ownIds((data) => (ownIds = data)),
|
|
view: (vnode) =>
|
|
m('.tab-page', [
|
|
LobbyName(),
|
|
m('.lobbies', m(SubscribedLeftLobbies), m(PublicLeftLobbies)),
|
|
m('.setup', [
|
|
m('h5.selectidentity', 'Select identity to use'),
|
|
ownIds.map((nick) =>
|
|
m(
|
|
'.identity' +
|
|
(ChatLobbyModel.currentLobby.gxs_id === nick ? '.selectedidentity' : ''),
|
|
{
|
|
onclick: () => ChatLobbyModel.setupAction(m.route.param('lobby'), nick),
|
|
},
|
|
rs.userList.username(nick)
|
|
)
|
|
),
|
|
]),
|
|
]),
|
|
};
|
|
};
|
|
|
|
/*
|
|
/rsMsgs/initiateDistantChatConnexion
|
|
* @param[in] to_pid RsGxsId to start the connection
|
|
* @param[in] from_pid owned RsGxsId who start the connection
|
|
* @param[out] pid distant chat id
|
|
* @param[out] error_code if the connection can't be stablished
|
|
* @param[in] notify notify remote that the connection is stablished
|
|
*/
|
|
const LayoutCreateDistant = () => {
|
|
let ownIds = [];
|
|
return {
|
|
oninit: () => peopleUtil.ownIds((data) => (ownIds = data)),
|
|
view: (vnode) =>
|
|
m('.tab-page', [
|
|
m('.createDistantChat', [
|
|
'choose identitiy to chat with ',
|
|
rs.userList.username(m.route.param('lobby')),
|
|
ownIds.map((id) =>
|
|
m(
|
|
'.identity',
|
|
{
|
|
onclick: () =>
|
|
rs.rsJsonApiRequest(
|
|
'/rsMsgs/initiateDistantChatConnexion',
|
|
{
|
|
to_pid: m.route.param('lobby'),
|
|
from_pid: id,
|
|
notify: true,
|
|
},
|
|
(result) => {
|
|
console.info('initiateDistantChatConnexion', result);
|
|
m.route.set('/chat/:lobbyid', { lobbyid: result.pid });
|
|
}
|
|
),
|
|
},
|
|
rs.userList.username(id)
|
|
)
|
|
),
|
|
]),
|
|
]),
|
|
};
|
|
};
|
|
|
|
module.exports = {
|
|
oninit: () => {
|
|
ChatRoomsModel.loadSubscribedRooms();
|
|
ChatRoomsModel.loadPublicRooms();
|
|
},
|
|
view: (vnode) => {
|
|
if (m.route.param('lobby') === undefined) {
|
|
return m(Layout);
|
|
} else if (m.route.param('subaction') === 'setup') {
|
|
return m(LayoutSetup);
|
|
} else if (m.route.param('subaction') === 'createdistantchat') {
|
|
return m(LayoutCreateDistant);
|
|
} else {
|
|
return m(LayoutSingle);
|
|
}
|
|
},
|
|
};
|