mirror of
https://github.com/matrix-org/sliding-sync.git
synced 2025-03-10 13:37:11 +00:00
237 lines
8.4 KiB
JavaScript
237 lines
8.4 KiB
JavaScript
/*
|
||
* This file contains code to map data structures to actual HTML elements.
|
||
* It is mostly functional and boring and it does not include any sliding sync specific data.
|
||
* In other words, if you want to learn about sliding sync, this isn't the file to look at.
|
||
*/
|
||
|
||
const membershipChangeText = (ev) => {
|
||
const prevContent = (ev.unsigned || {}).prev_content || {};
|
||
const prevMembership = prevContent.membership || "leave";
|
||
const nowMembership = ev.content.membership;
|
||
if (nowMembership != prevMembership) {
|
||
switch (nowMembership) {
|
||
case "join":
|
||
return ev.state_key + " joined the room";
|
||
case "leave":
|
||
return ev.state_key + " left the room";
|
||
case "ban":
|
||
return ev.sender + " banned " + ev.state_key + " from the room";
|
||
case "invite":
|
||
return ev.sender + " invited " + ev.state_key + " to the room";
|
||
case "knock":
|
||
return ev.state_key + " knocked on the room";
|
||
}
|
||
}
|
||
if (nowMembership == prevMembership && nowMembership == "join") {
|
||
// display name or avatar change
|
||
if (prevContent.displayname !== ev.content.displayname) {
|
||
return (
|
||
ev.state_key + " set their name to " + ev.content.displayname
|
||
);
|
||
}
|
||
if (prevContent.avatar_url !== ev.content.avatar_url) {
|
||
return ev.state_key + " changed their profile picture";
|
||
}
|
||
}
|
||
return ev.type + " event";
|
||
};
|
||
|
||
const textForEvent = (ev) => {
|
||
let body = "";
|
||
switch (ev.type) {
|
||
case "m.room.message":
|
||
body = ev.content.body;
|
||
break;
|
||
case "m.room.member":
|
||
body = membershipChangeText(ev);
|
||
break;
|
||
case "m.reaction":
|
||
body = "reacted with " + (ev.content["m.relates_to"] || {}).key;
|
||
break;
|
||
default:
|
||
body = ev.type + " event";
|
||
break;
|
||
}
|
||
return body;
|
||
};
|
||
|
||
const randomName = (i, long) => {
|
||
if (i % 17 === 0) {
|
||
return long
|
||
? "Ever have that feeling where you’re not sure if you’re awake or dreaming?"
|
||
: "There is no spoon";
|
||
} else if (i % 13 === 0) {
|
||
return long
|
||
? "Choice is an illusion created between those with power and those without."
|
||
: "Get Up Trinity";
|
||
} else if (i % 11 === 0) {
|
||
return long
|
||
? "That’s how it is with people. Nobody cares how it works as long as it works."
|
||
: "I know kung fu";
|
||
} else if (i % 7 === 0) {
|
||
return long
|
||
? "The body cannot live without the mind."
|
||
: "Free your mind";
|
||
} else if (i % 5 === 0) {
|
||
return long
|
||
? "Perhaps we are asking the wrong questions…"
|
||
: "Agent Smith";
|
||
} else if (i % 3 === 0) {
|
||
return long
|
||
? "You've been living in a dream world, Neo."
|
||
: "Mr Anderson";
|
||
} else {
|
||
return long ? "Mr. Wizard, get me the hell out of here! " : "Morpheus";
|
||
}
|
||
};
|
||
|
||
const zeroPad = (n) => {
|
||
if (n < 10) {
|
||
return "0" + n;
|
||
}
|
||
return n;
|
||
};
|
||
|
||
const formatTimestamp = (originServerTs) => {
|
||
const d = new Date(originServerTs);
|
||
return (
|
||
d.toDateString() +
|
||
" " +
|
||
zeroPad(d.getHours()) +
|
||
":" +
|
||
zeroPad(d.getMinutes()) +
|
||
":" +
|
||
zeroPad(d.getSeconds())
|
||
);
|
||
};
|
||
|
||
const mxcToUrl = (syncv2ServerUrl, mxc) => {
|
||
const path = mxc.substr("mxc://".length);
|
||
if (!path) {
|
||
return;
|
||
}
|
||
return `${syncv2ServerUrl}/_matrix/media/r0/thumbnail/${path}?width=64&height=64&method=crop`;
|
||
};
|
||
|
||
export const renderRoomHeader = (room, syncv2ServerUrl) => {
|
||
document.getElementById("selectedroomname").textContent =
|
||
room.name || room.room_id;
|
||
if (room.avatar) {
|
||
document.getElementById("selectedroomavatar").src =
|
||
mxcToUrl(syncv2ServerUrl, room.avatar) || "/client/placeholder.svg";
|
||
} else {
|
||
document.getElementById("selectedroomavatar").src =
|
||
"/client/placeholder.svg";
|
||
}
|
||
if (room.topic) {
|
||
document.getElementById("selectedroomtopic").textContent = room.topic;
|
||
} else {
|
||
document.getElementById("selectedroomtopic").textContent = "";
|
||
}
|
||
};
|
||
|
||
export const renderEvent = (eventIdKey, ev) => {
|
||
const template = document.getElementById("messagetemplate");
|
||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template#avoiding_documentfragment_pitfall
|
||
const msgCell = template.content.firstElementChild.cloneNode(true);
|
||
msgCell.setAttribute("id", eventIdKey);
|
||
msgCell.getElementsByClassName("msgsender")[0].textContent = ev.sender;
|
||
msgCell.getElementsByClassName("msgtimestamp")[0].textContent =
|
||
formatTimestamp(ev.origin_server_ts);
|
||
let body = textForEvent(ev);
|
||
msgCell.getElementsByClassName("msgcontent")[0].textContent = body;
|
||
return msgCell;
|
||
};
|
||
|
||
/**
|
||
* Render a room cell for the room list.
|
||
* @param {Element} roomCell The DOM element to put the details into. The cell must be already initialised with `roomCellTemplate`.
|
||
* @param {object} room The room data model, which can be null to indicate a placeholder.
|
||
*/
|
||
export const renderRoomCell = (
|
||
roomCell,
|
||
room,
|
||
index,
|
||
isHighlighted,
|
||
syncv2ServerUrl
|
||
) => {
|
||
// if this child is a placeholder and it was previously a placeholder then do nothing.
|
||
if (!room && roomCell.getAttribute("x-placeholder") === "yep") {
|
||
return;
|
||
}
|
||
const roomNameSpan = roomCell.getElementsByClassName("roomname")[0];
|
||
const roomContentSpan = roomCell.getElementsByClassName("roomcontent")[0];
|
||
const roomSenderSpan = roomCell.getElementsByClassName("roomsender")[0];
|
||
const roomTimestampSpan =
|
||
roomCell.getElementsByClassName("roomtimestamp")[0];
|
||
const unreadCountSpan = roomCell.getElementsByClassName("unreadcount")[0];
|
||
|
||
// remove previous unread counts
|
||
unreadCountSpan.textContent = "";
|
||
unreadCountSpan.classList.remove("unreadcountnotify");
|
||
unreadCountSpan.classList.remove("unreadcounthighlight");
|
||
|
||
if (!room) {
|
||
// make a placeholder
|
||
roomNameSpan.textContent = randomName(index, false);
|
||
roomNameSpan.style = "background: #e0e0e0; color: #e0e0e0;";
|
||
roomContentSpan.textContent = randomName(index, true);
|
||
roomContentSpan.style = "background: #e0e0e0; color: #e0e0e0;";
|
||
roomSenderSpan.textContent = "";
|
||
roomTimestampSpan.textContent = "";
|
||
roomCell.getElementsByClassName("roomavatar")[0].src =
|
||
"/client/placeholder.svg";
|
||
roomCell.style = "";
|
||
roomCell.setAttribute("x-placeholder", "yep");
|
||
return;
|
||
}
|
||
|
||
roomCell.removeAttribute("x-placeholder"); // in case this was previously a placeholder
|
||
roomCell.style = "";
|
||
roomNameSpan.textContent = room.name || room.room_id;
|
||
roomNameSpan.style = "";
|
||
roomContentSpan.style = "";
|
||
if (room.avatar) {
|
||
roomCell.getElementsByClassName("roomavatar")[0].src =
|
||
mxcToUrl(syncv2ServerUrl, room.avatar) || "/client/placeholder.svg";
|
||
} else {
|
||
roomCell.getElementsByClassName("roomavatar")[0].src =
|
||
"/client/placeholder.svg";
|
||
}
|
||
if (isHighlighted) {
|
||
roomCell.style = "background: #d7d7f7";
|
||
}
|
||
if (room.highlight_count > 0) {
|
||
// use the notification count instead to avoid counts dropping down. This matches ele-web
|
||
unreadCountSpan.textContent = room.notification_count + "";
|
||
unreadCountSpan.classList.add("unreadcounthighlight");
|
||
} else if (room.notification_count > 0) {
|
||
unreadCountSpan.textContent = room.notification_count + "";
|
||
unreadCountSpan.classList.add("unreadcountnotify");
|
||
} else {
|
||
unreadCountSpan.textContent = "";
|
||
}
|
||
|
||
if (room.obsolete) {
|
||
roomContentSpan.textContent = "";
|
||
roomSenderSpan.textContent = room.obsolete;
|
||
} else if (room.timeline && room.timeline.length > 0) {
|
||
const mostRecentEvent = room.timeline[room.timeline.length - 1];
|
||
roomSenderSpan.textContent = mostRecentEvent.sender;
|
||
|
||
roomTimestampSpan.textContent = formatTimestamp(
|
||
mostRecentEvent.origin_server_ts
|
||
);
|
||
|
||
const body = textForEvent(mostRecentEvent);
|
||
if (mostRecentEvent.type === "m.room.member") {
|
||
roomContentSpan.textContent = "";
|
||
roomSenderSpan.textContent = body;
|
||
} else {
|
||
roomContentSpan.textContent = body;
|
||
}
|
||
} else {
|
||
roomContentSpan.textContent = "";
|
||
}
|
||
};
|