mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-14 11:05:47 +05:00
chat: switch chat in 3 column style
This commit is contained in:
parent
8d5b775028
commit
64fcb0c530
@ -60,6 +60,9 @@ Usage
|
||||
-----
|
||||
Go to `RsNewWebUI/webui/` and open the `index.html` file in your browser.
|
||||
|
||||
### References:
|
||||
* Mithril: https://mithril.js.org/hyperscript.html
|
||||
|
||||
Contributing
|
||||
------------
|
||||
### Bug Reports & Feature requests
|
||||
|
||||
@ -2,18 +2,61 @@
|
||||
margin: 10px;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 20px;
|
||||
}.lobby h5 {
|
||||
}
|
||||
|
||||
.lobby .mainname {
|
||||
margin: 20px;
|
||||
font-weight: 100;
|
||||
font-size: 1.2em;
|
||||
}.lobby > p {
|
||||
font-size: 0.95em;
|
||||
color: #666;
|
||||
margin-left: 25px;
|
||||
}
|
||||
.lobby.subscribed:hover {
|
||||
|
||||
.topic {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.lobby > .topic {
|
||||
font-size: 0.95em;
|
||||
margin-left: 25px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.lefttitle {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 0;
|
||||
font-weight: 100;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.leftname {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
padding:5px;
|
||||
font-weight: 100;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.leftlobby > .topic {
|
||||
font-size: 0.75em;
|
||||
margin-left: 15px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.subscribed {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.leftlobby {
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 10px;
|
||||
margin-top: 5px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.leftlobby.selected-lobby {
|
||||
color: white;
|
||||
background-color: #3ba4d7;
|
||||
}
|
||||
|
||||
.rightbar {
|
||||
position: absolute;
|
||||
width: 185px;
|
||||
@ -32,25 +75,20 @@
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.chatMessage {
|
||||
.lobbies {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
height: 85px;
|
||||
width: 185px;
|
||||
left:15px ;
|
||||
bottom: 15px;
|
||||
right: 215px;
|
||||
left: 15px;
|
||||
}
|
||||
|
||||
textarea.chatMsg {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 130px;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.messages {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
top: 130px;
|
||||
left: 15px;
|
||||
left: 215px;
|
||||
right: 215px;
|
||||
bottom: 115px;
|
||||
overflow: auto;
|
||||
@ -67,4 +105,18 @@ textarea.chatMsg {
|
||||
.username {
|
||||
color: darkgreen;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.chatMessage {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
height: 85px;
|
||||
bottom: 15px;
|
||||
right: 215px;
|
||||
left: 215px;
|
||||
}
|
||||
|
||||
textarea.chatMsg {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@ -21,6 +21,7 @@ function loadLobbyDetails(id, apply) {
|
||||
|
||||
let ChatRoomsModel = {
|
||||
allRooms: [],
|
||||
knownSubscrIds:[], // to exclude subscribed from public rooms (subscribedRooms filled to late)
|
||||
subscribedRooms: {},
|
||||
loadPublicRooms() {
|
||||
// TODO: this doesn't preserve id of rooms,
|
||||
@ -32,23 +33,28 @@ let ChatRoomsModel = {
|
||||
);
|
||||
},
|
||||
loadSubscribedRooms() {
|
||||
ChatRoomsModel.subscribedRooms = {};
|
||||
// ChatRoomsModel.subscribedRooms = {};
|
||||
rs.rsJsonApiRequest('/rsMsgs/getChatLobbyList', {},
|
||||
data => data.map(id => loadLobbyDetails(id, info => ChatRoomsModel.subscribedRooms[id] = info)),
|
||||
data => {
|
||||
ChatRoomsModel.knownSubscrIds = data;
|
||||
let rooms = {};
|
||||
data.map(id => loadLobbyDetails(id, info => rooms[id] = info));
|
||||
ChatRoomsModel.subscribedRooms = rooms;
|
||||
},
|
||||
true, {},
|
||||
// Custom deserializer NOTE:
|
||||
// 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`.
|
||||
// Instead of parsing using JSON.parse, this funciton manually
|
||||
// Instead of parsing using JSON.parse, this function manually
|
||||
// extracts all numbers and stores them as strings
|
||||
// Note the g flag. The match will return an array of strings
|
||||
(response) => response.match(/\d+/g),
|
||||
)
|
||||
},
|
||||
subscribed(info) {
|
||||
return this.subscribedRooms.hasOwnProperty(info.lobby_id.xstr64);
|
||||
return this.knownSubscrIds.includes(info.lobby_id.xstr64);
|
||||
},
|
||||
};
|
||||
|
||||
@ -69,10 +75,10 @@ const ChatLobbyModel = {
|
||||
chatId(action) {
|
||||
return {type:3,lobby_id:{xstr64:m.route.param('lobby')}};
|
||||
},
|
||||
loadLobby () {
|
||||
loadLobbyDetails(m.route.param('lobby'), detail => {
|
||||
loadLobby (currentlobbyid) {
|
||||
loadLobbyDetails(currentlobbyid, detail => {
|
||||
this.currentLobby = detail;
|
||||
let lobbyid = m.route.param('lobby');
|
||||
let lobbyid = currentlobbyid;
|
||||
// apply existing messages to current lobby view
|
||||
rs.events[15].chatMessages(this.chatId(),rs.events[15], l => (this.messages = l.map(printMessage)));
|
||||
// register for chatEvents for future messages
|
||||
@ -108,37 +114,50 @@ const ChatLobbyModel = {
|
||||
() => '{"id":{"type": 3,"lobby_id":' + m.route.param('lobby') + '}, "msg":' + JSON.stringify(msg) + '}'
|
||||
);
|
||||
},
|
||||
selected(info, selName, defaultName) {
|
||||
let 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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const Lobby = () => {
|
||||
let info = {};
|
||||
let tagname = '';
|
||||
let onclick = e => {};
|
||||
let lobbytagname = '';
|
||||
return {
|
||||
oninit: (v) => info = v.attrs.info,
|
||||
view: (v) => m( '.lobby.' + (ChatRoomsModel.subscribed(v.attrs.info) ? 'subscribed':'public'), {
|
||||
key: v.attrs.info.lobby_id.xstr64,
|
||||
onclick: e => {
|
||||
if (ChatRoomsModel.subscribed(v.attrs.info)) {
|
||||
m.route.set('/chat/:lobby', {
|
||||
lobby: v.attrs.info.lobby_id.xstr64
|
||||
});
|
||||
}
|
||||
},
|
||||
oninit: (v) => {
|
||||
info = v.attrs.info;
|
||||
tagname = v.attrs.tagname;
|
||||
onclick = v.attrs.onclick || (e => {});
|
||||
lobbytagname= v.attrs.lobbytagname || 'h5.mainname';
|
||||
},
|
||||
view: v => {
|
||||
return m(ChatLobbyModel.selected(info, '.selected-lobby', tagname), {
|
||||
key: info.lobby_id.xstr64,
|
||||
onclick: onclick,
|
||||
}, [
|
||||
m('h5', info.lobby_name === '' ? '<unnamed>' : info.lobby_name),
|
||||
m('p', info.lobby_topic),
|
||||
]),
|
||||
m(lobbytagname,info.lobby_name === '' ? '<unnamed>' : info.lobby_name),
|
||||
m('.topic', info.lobby_topic),
|
||||
]);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const SubscribedLobbies = () => {
|
||||
lobbies = [];
|
||||
return {
|
||||
oninit: (v) => ChatRoomsModel.loadSubscribedRooms(),
|
||||
view: () => m('.widget', [
|
||||
m('h3', 'Subscribed chat rooms'),
|
||||
m('hr'),
|
||||
Object.values(ChatRoomsModel.subscribedRooms).map(info => m(Lobby, {
|
||||
info
|
||||
info, tagname:'.lobby.subscribed', onclick: e => m.route.set('/chat/:lobby', { lobby: info.lobby_id.xstr64 })
|
||||
})),
|
||||
]),
|
||||
};
|
||||
@ -146,12 +165,11 @@ const SubscribedLobbies = () => {
|
||||
|
||||
const PublicLobbies = () => {
|
||||
return {
|
||||
oninit: () => ChatRoomsModel.loadPublicRooms(),
|
||||
view: () => m('.widget', [
|
||||
m('h3', 'Public chat rooms'),
|
||||
m('hr'),
|
||||
ChatRoomsModel.allRooms.filter(info => !ChatRoomsModel.subscribed(info)).map(info => m(Lobby, {
|
||||
info,
|
||||
info, tagname:'.lobby.public',
|
||||
})),
|
||||
])
|
||||
};
|
||||
@ -159,6 +177,10 @@ const PublicLobbies = () => {
|
||||
|
||||
const Layout = () => {
|
||||
return {
|
||||
oninit: () => {
|
||||
ChatRoomsModel.loadSubscribedRooms();
|
||||
ChatRoomsModel.loadPublicRooms();
|
||||
},
|
||||
view: vnode => m('.tab-page', [
|
||||
m(SubscribedLobbies),
|
||||
m(PublicLobbies),
|
||||
@ -166,11 +188,51 @@ const Layout = () => {
|
||||
};
|
||||
};
|
||||
|
||||
const LobbyList = () => {
|
||||
let rooms= [];
|
||||
let tagname= '';
|
||||
let lobbytagname= '';
|
||||
let onclick = (info => (() => {}));
|
||||
return {
|
||||
oninit: vnode => {
|
||||
rooms = vnode.attrs.rooms;
|
||||
tagname = vnode.attrs.tagname;
|
||||
lobbytagname= vnode.attrs.lobbytagname;
|
||||
onclick=vnode.attrs.onclick||(() => (() => {}));
|
||||
},
|
||||
view: vnode => rooms.map(info => m(Lobby, {
|
||||
info,
|
||||
tagname: tagname,
|
||||
lobbytagname,
|
||||
onclick: onclick(info),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
const LayoutSingle = () => {
|
||||
return {
|
||||
oninit: ChatLobbyModel.loadLobby(),
|
||||
oninit: () => {
|
||||
ChatRoomsModel.loadSubscribedRooms();
|
||||
ChatRoomsModel.loadPublicRooms();
|
||||
ChatLobbyModel.loadLobby(m.route.param('lobby'));
|
||||
},
|
||||
view: vnode => m('.tab-page', [
|
||||
m('h3.lobbyName', ChatLobbyModel.currentLobby.lobby_name),
|
||||
m('.lobbies',
|
||||
m('h5.lefttitle', 'subscribed:'),
|
||||
m('hr'),
|
||||
m(LobbyList, {
|
||||
rooms: Object.values(ChatRoomsModel.subscribedRooms),
|
||||
tagname: '.leftlobby.subscribed',
|
||||
lobbytagname:'h5.leftname',
|
||||
onclick: ChatLobbyModel.switchToEvent,
|
||||
}),
|
||||
m('h5.lefttitle', 'public:'),
|
||||
m('hr'),
|
||||
Object.values(ChatRoomsModel.allRooms).filter(info => !ChatRoomsModel.subscribed(info)).map(info => m(Lobby, {
|
||||
info, tagname: '.leftlobby.public', lobbytagname:'h5.leftname',
|
||||
})),
|
||||
),
|
||||
m('.messages', ChatLobbyModel.messages),
|
||||
m('.rightbar', ChatLobbyModel.users),
|
||||
m('.chatMessage', {}, m("textarea.chatMsg", {
|
||||
|
||||
@ -100,30 +100,40 @@ function computeIfMissing(map, key, missing = () => ({})) {
|
||||
function deeperIfExist(map, key, action) {
|
||||
if (map.hasOwnProperty(key)) {
|
||||
action(map[key]);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const eventQueue = {
|
||||
events: {
|
||||
15: { // Chat-Messages
|
||||
types: {
|
||||
3: chat_id => chat_id.lobby_id.xstr64, // lobby_id
|
||||
},
|
||||
messages: {},
|
||||
chatMessages: (chat_id, owner, action) => deeperIfExist(
|
||||
owner.types,
|
||||
chat_id.type,
|
||||
keyfn => action(computeIfMissing(computeIfMissing(owner.messages,chat_id.type), keyfn(chat_id),()=>[]))
|
||||
),
|
||||
handler: (event,owner) => owner.chatMessages(event.mChatMessage.chat_id, owner, r => {
|
||||
console.info(['adding chat' ,r , event.mChatMessage])
|
||||
r.push(event.mChatMessage);
|
||||
owner.notify(event.mChatMessage);
|
||||
}),
|
||||
notify: () => {},
|
||||
types: {
|
||||
3: chat_id => chat_id.lobby_id.xstr64, // lobby_id
|
||||
},
|
||||
messages: {},
|
||||
chatMessages: (chat_id, owner, action) => deeperIfExist(
|
||||
owner.types,
|
||||
chat_id.type,
|
||||
keyfn => action(computeIfMissing(computeIfMissing(owner.messages,chat_id.type), keyfn(chat_id),()=>[]))
|
||||
),
|
||||
handler: (event,owner) => owner.chatMessages(event.mChatMessage.chat_id, owner, r => {
|
||||
console.info(['adding chat' ,r , event.mChatMessage]);
|
||||
r.push(event.mChatMessage);
|
||||
owner.notify(event.mChatMessage);
|
||||
}),
|
||||
notify: () => {},
|
||||
},
|
||||
8: { // Circles (ignore in the meantime)
|
||||
handler: (event,owner) => {},
|
||||
}
|
||||
},
|
||||
handler: event => {
|
||||
if (!deeperIfExist(eventQueue.events, event.mType, owner => owner.handler(event, owner))) {
|
||||
console.info(event);
|
||||
};
|
||||
},
|
||||
handler: event => deeperIfExist(eventQueue.events, event.mType, owner => owner.handler(event, owner)),
|
||||
}
|
||||
|
||||
const userList = {
|
||||
@ -189,11 +199,10 @@ function startEventQueue(info, loginHeader = {}, displayAuthError = () => {}, di
|
||||
}
|
||||
} else if(data.hasOwnProperty('event')) {
|
||||
data.event.queueSize = currIndex;
|
||||
console.info(data.event);
|
||||
eventQueue.handler(data.event);
|
||||
}
|
||||
}
|
||||
if (currIndex > 1e6) { // max 1 MB eventQueue
|
||||
if (currIndex > 1e5) { // max 100 kB eventQueue
|
||||
startEventQueue('restart queue');
|
||||
xhr.abort();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user