mirror of
https://gitgud.io/BondageProjects/Bondage-College.git
synced 2025-04-14 12:29:15 +00:00
Merge branch 'friendlist' into 'master'
ENH: Use semantic HTML for the friend list and add a new column for room types See merge request BondageProjects/Bondage-College!5471
This commit is contained in:
commit
4e79439d91
9 changed files with 311 additions and 123 deletions
BondageClub
CSS
Icons
Screens/Character/FriendList
Scripts
|
@ -33,6 +33,7 @@
|
|||
padding: var(--small-gap);
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#friend-list-search-input {
|
||||
|
@ -61,17 +62,19 @@
|
|||
/* #endregion */
|
||||
|
||||
/* #region HEADER */
|
||||
|
||||
#friend-list-header {
|
||||
min-height: var(--row-height);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--text-color);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#friend-list-header .friend-list-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#friend-list-header .friend-list-row:hover {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
#friend-list-header-hr {
|
||||
width: 80%;
|
||||
}
|
||||
|
@ -105,6 +108,60 @@
|
|||
#friend-list-beep-dialog:not([data-received]) .fl-beep-sent-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ChatRoomType {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.15em;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.friend-list-icon-container {
|
||||
position: relative;
|
||||
height: var(--row-height);
|
||||
width: var(--row-height);
|
||||
max-width: 86px;
|
||||
max-height: 86px;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.friend-list-icon-container > .button-tooltip {
|
||||
--tooltip-gap: 0.15em;
|
||||
}
|
||||
|
||||
.friend-list-icon {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
@supports selector(:has(*)) {
|
||||
.friend-list-icon-container:hover:not(:has(.button-tooltip:hover)) > .button-tooltip {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
@supports not selector(:has(*)) {
|
||||
.friend-list-icon-container:hover > .button-tooltip {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.friend-list-icon-small {
|
||||
pointer-events: none;
|
||||
height: var(--row-height);
|
||||
width: var(--row-height);
|
||||
max-width: 50px;
|
||||
max-height: 50px;
|
||||
margin-inline: 0.15em;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
/* #endregion */
|
||||
|
||||
/* #region FRIENDLIST */
|
||||
|
@ -124,17 +181,27 @@
|
|||
width: calc(100% - var(--button-size));
|
||||
}
|
||||
|
||||
.friend-list-row {
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-evenly;
|
||||
#friend-list-table th {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.friend-list-row * {
|
||||
.friend-list-row {
|
||||
color: var(--text-color);
|
||||
min-height: var(--row-height);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: space-evenly;
|
||||
padding: unset;
|
||||
margin: var(--small-gap) 0;
|
||||
}
|
||||
|
||||
.friend-list-row > * {
|
||||
vertical-align: middle;
|
||||
text-justify: center;
|
||||
padding: unset;
|
||||
}
|
||||
|
||||
.friend-list-row:hover {
|
||||
color: yellow;
|
||||
}
|
||||
|
@ -147,10 +214,6 @@
|
|||
white-space: preserve;
|
||||
}
|
||||
|
||||
#friend-list .friend-list-column {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#friend-list-member-number,
|
||||
.MemberNumber {
|
||||
width: 10%;
|
||||
|
@ -168,8 +231,8 @@
|
|||
gap: var(--small-gap);
|
||||
}
|
||||
|
||||
.RelationType img {
|
||||
height: min(5dvh, 2.5dvw);
|
||||
.RelationType {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.friend-list-link {
|
||||
|
|
BIN
BondageClub/Icons/FemaleInverted.png
Normal file
BIN
BondageClub/Icons/FemaleInverted.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 3.5 KiB |
BIN
BondageClub/Icons/GenderInvert.png
Normal file
BIN
BondageClub/Icons/GenderInvert.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2 KiB |
BIN
BondageClub/Icons/MaleInverted.png
Normal file
BIN
BondageClub/Icons/MaleInverted.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 3.6 KiB |
BIN
BondageClub/Icons/PrivateInvert.png
Normal file
BIN
BondageClub/Icons/PrivateInvert.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2.1 KiB |
|
@ -1,6 +1,6 @@
|
|||
type FriendListModes = FriendListMode[];
|
||||
type FriendListMode = "OnlineFriends" | "Beeps" | "AllFriends";
|
||||
type FriendListSortingMode = 'None' | 'MemberName' | 'MemberNickname' | 'MemberNumber' | 'ChatRoomName' | 'RelationType';
|
||||
type FriendListSortingMode = 'None' | 'MemberName' | 'MemberNickname' | 'MemberNumber' | 'ChatRoomName' | 'RelationType' | 'ChatRoomType';
|
||||
type FriendListSortingDirection = 'Asc' | 'Desc';
|
||||
|
||||
type FriendListReturn<T extends ModuleType> = { Screen: ModuleScreens[T], Module: T, IsInChatRoom?: boolean, hasScrolledChat?: boolean };
|
||||
|
@ -19,6 +19,7 @@ type FriendRawRoom = {
|
|||
name?: string;
|
||||
caption: string;
|
||||
canSearchRoom: boolean;
|
||||
types: FriendListIcon[];
|
||||
};
|
||||
|
||||
type FriendRawBeep = {
|
||||
|
@ -27,3 +28,12 @@ type FriendRawBeep = {
|
|||
hasMessage?: boolean;
|
||||
canBeep?: boolean;
|
||||
};
|
||||
|
||||
interface FriendListIcon {
|
||||
/** The {@link HTMLImageElement.src} of the icon */
|
||||
src: string;
|
||||
/** The `Character/FriendList` {@link TextGet} key of the icon's tooltip */
|
||||
tooltipKey: string;
|
||||
/** A string to-be used for sorting the icon-containing column cells */
|
||||
sortKey: string;
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ function FriendListLoad() {
|
|||
tag: 'input',
|
||||
attributes: {
|
||||
id: FriendListIDs.searchInput,
|
||||
type: 'text',
|
||||
type: 'search',
|
||||
maxLength: 100,
|
||||
},
|
||||
eventListeners: {
|
||||
|
@ -198,71 +198,87 @@ function FriendListLoad() {
|
|||
}
|
||||
),
|
||||
ElementCreate({
|
||||
tag: 'div',
|
||||
tag: 'table',
|
||||
attributes: {
|
||||
id: FriendListIDs.friendListTable
|
||||
id: FriendListIDs.friendListTable,
|
||||
"aria-labelledby": FriendListIDs.modeTitle,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
tag: 'div',
|
||||
tag: 'thead',
|
||||
attributes: {
|
||||
id: FriendListIDs.header
|
||||
},
|
||||
classList: ['friend-list-row'],
|
||||
children: [
|
||||
ElementButton.Create(
|
||||
"friend-list-member-name",
|
||||
() => FriendListChangeSortingMode("MemberName"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link'],
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
"friend-list-member-number",
|
||||
() => FriendListChangeSortingMode("MemberNumber"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link'],
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
"friend-list-chat-room-name",
|
||||
() => FriendListChangeSortingMode("ChatRoomName"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-online-friends-content', 'fl-beeps-content'],
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
"friend-list-relation-type",
|
||||
() => FriendListChangeSortingMode("RelationType"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-all-friends-content'],
|
||||
}},
|
||||
),
|
||||
{
|
||||
tag: "span",
|
||||
classList: ['friend-list-column', 'mode-specific-content', 'fl-online-friends-content'],
|
||||
tag: "tr",
|
||||
classList: ["friend-list-row"],
|
||||
children: [
|
||||
TextGet("ActionFriends")
|
||||
ElementButton.Create(
|
||||
"friend-list-member-name",
|
||||
() => FriendListChangeSortingMode("MemberName"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link'],
|
||||
attributes: { role: "columnheader" },
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
"friend-list-member-number",
|
||||
() => FriendListChangeSortingMode("MemberNumber"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link'],
|
||||
attributes: { role: "columnheader" },
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
"friend-list-chat-room-type",
|
||||
() => FriendListChangeSortingMode("ChatRoomType"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-online-friends-content', 'fl-beeps-content'],
|
||||
attributes: { role: "columnheader" },
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
"friend-list-chat-room-name",
|
||||
() => FriendListChangeSortingMode("ChatRoomName"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-online-friends-content', 'fl-beeps-content'],
|
||||
attributes: { role: "columnheader" },
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
"friend-list-relation-type",
|
||||
() => FriendListChangeSortingMode("RelationType"),
|
||||
{ noStyling: true },
|
||||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-all-friends-content'],
|
||||
attributes: { role: "columnheader" },
|
||||
}},
|
||||
),
|
||||
{
|
||||
tag: "th",
|
||||
classList: ['friend-list-column', 'mode-specific-content', 'fl-online-friends-content'],
|
||||
attributes: { scope: "col" },
|
||||
children: [TextGet("ActionFriends")],
|
||||
},
|
||||
{
|
||||
tag: "th",
|
||||
classList: ['friend-list-column', 'mode-specific-content', 'fl-beeps-content'],
|
||||
attributes: { scope: "col" },
|
||||
children: [TextGet("ActionRead")],
|
||||
},
|
||||
{
|
||||
tag: "th",
|
||||
classList: ['friend-list-column', 'mode-specific-content', 'fl-all-friends-content'],
|
||||
attributes: { scope: "col" },
|
||||
children: [TextGet("ActionDelete")],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "span",
|
||||
classList: ['friend-list-column', 'mode-specific-content', 'fl-beeps-content'],
|
||||
children: [
|
||||
TextGet("ActionRead")
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "span",
|
||||
classList: ['friend-list-column', 'mode-specific-content', 'fl-all-friends-content'],
|
||||
children: [
|
||||
TextGet("ActionDelete")
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -272,7 +288,7 @@ function FriendListLoad() {
|
|||
}
|
||||
},
|
||||
{
|
||||
tag: 'div',
|
||||
tag: 'tbody',
|
||||
classList: ["scroll-box"],
|
||||
attributes: {
|
||||
id: FriendListIDs.friendList
|
||||
|
@ -504,7 +520,7 @@ function FriendListBeepMenuSend() {
|
|||
ChatRoomName: FriendListBeepShowRoom ? ChatRoomData?.Name : undefined,
|
||||
ChatRoomSpace: FriendListBeepShowRoom ? ChatRoomData?.Space : undefined,
|
||||
Sent: true,
|
||||
Private: false,
|
||||
Private: FriendListBeepShowRoom ? !ChatRoomData?.Visibility.includes("All") : undefined,
|
||||
Time: new Date(),
|
||||
Message: msg || undefined
|
||||
});
|
||||
|
@ -537,6 +553,15 @@ function FriendListChatSearch(room) {
|
|||
ElementValue("InputSearch", ChatSearchMuffle(room));
|
||||
}
|
||||
|
||||
/** @satisfies {{ [key in (ServerChatRoomSpace | "Private")]: FriendListIcon }} */
|
||||
const FriendListIconMapping = {
|
||||
"": { src: "./Icons/FemaleInvert.png", tooltipKey: "TypeFemale", sortKey: "F " },
|
||||
M: { src: "./Icons/MaleInvert.png", tooltipKey: "TypeMale", sortKey: "M " },
|
||||
X: { src: "./Icons/GenderInvert.png", tooltipKey: "TypeMixed", sortKey: "FM" },
|
||||
Asylum: { src: "./Icons/Asylum.png", tooltipKey: "TypeAsylum", sortKey: "A " },
|
||||
Private: { src: "./Icons/PrivateInvert.png", tooltipKey: "TypePrivate", sortKey: "P" },
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads the friend list data into the HTML div element.
|
||||
* @param {ServerFriendInfo[]} data - An array of data, we receive from the server
|
||||
|
@ -559,7 +584,6 @@ function FriendListLoadFriendList(data) {
|
|||
const BeepCaption = InterfaceTextGet("Beep");
|
||||
const DeleteCaption = InterfaceTextGet("Delete");
|
||||
const ConfirmDeleteCaption = InterfaceTextGet("ConfirmDelete");
|
||||
const PrivateRoomCaption = InterfaceTextGet("PrivateRoom");
|
||||
const SentCaption = InterfaceTextGet("SentBeep");
|
||||
const ReceivedCaption = InterfaceTextGet("ReceivedBeep");
|
||||
const MailCaption = InterfaceTextGet("BeepWithMail");
|
||||
|
@ -601,15 +625,28 @@ function FriendListLoadFriendList(data) {
|
|||
});
|
||||
if (infoChanged) ServerPlayerRelationsSync();
|
||||
|
||||
/** @satisfies {Record<string, FriendListSortingMode>} */
|
||||
const columnHeaders = {
|
||||
"friend-list-member-name": `${TextGet("MemberName")} ${FriendListSortingMode === "MemberName" ? sortingSymbol : "↕"}`,
|
||||
"friend-list-member-number": `${TextGet("MemberNumber")} ${FriendListSortingMode === "MemberNumber" ? sortingSymbol : "↕"}`,
|
||||
"friend-list-chat-room-name": `${TextGet("ChatRoomName")} ${FriendListSortingMode === "ChatRoomName" ? sortingSymbol : "↕"}`,
|
||||
"friend-list-relation-type": `${TextGet("FriendType")} ${FriendListSortingMode === "RelationType" ? sortingSymbol : "↕"}`,
|
||||
"friend-list-member-name": "MemberName",
|
||||
"friend-list-member-number": "MemberNumber",
|
||||
"friend-list-chat-room-name": "ChatRoomName",
|
||||
"friend-list-chat-room-type": "ChatRoomType",
|
||||
"friend-list-relation-type": "RelationType",
|
||||
};
|
||||
CommonEntries(columnHeaders).forEach(([id, textContent]) => {
|
||||
CommonEntries(columnHeaders).forEach(([id, modeName]) => {
|
||||
const elem = document.getElementById(id);
|
||||
elem.textContent = textContent;
|
||||
const elemSortingSymbol = FriendListSortingMode === modeName ? sortingSymbol : "↕";
|
||||
elem.textContent = `${TextGet(modeName)} ${elemSortingSymbol}`;
|
||||
switch (elemSortingSymbol) {
|
||||
case "↑":
|
||||
elem.setAttribute("aria-sort", "ascending");
|
||||
break;
|
||||
case "↓":
|
||||
elem.setAttribute("aria-sort", "descending");
|
||||
break;
|
||||
default:
|
||||
elem.setAttribute("aria-sort", "none");
|
||||
}
|
||||
});
|
||||
|
||||
/** @type {FriendRawData[]} */
|
||||
|
@ -621,25 +658,20 @@ function FriendListLoadFriendList(data) {
|
|||
const originalChatRoomName = friend.ChatRoomName || '';
|
||||
const chatRoomSpaceCaption = InterfaceTextGet(`ChatRoomSpace${friend.ChatRoomSpace || "F"}`);
|
||||
const chatRoomName = ChatSearchMuffle(friend.ChatRoomName?.replaceAll('<', '<').replaceAll('>', '>') || undefined);
|
||||
let caption = '';
|
||||
const canSearchRoom = FriendListReturn?.Screen === 'ChatSearch' && ChatRoomSpace === (friend.ChatRoomSpace || '');
|
||||
const canBeep = true;
|
||||
|
||||
const rawCaption = [];
|
||||
if (chatRoomSpaceCaption && chatRoomName) rawCaption.push(`<i>${chatRoomSpaceCaption}</i>`);
|
||||
if (friend.Private) rawCaption.push(PrivateRoomCaption);
|
||||
if (chatRoomName) rawCaption.push(chatRoomName);
|
||||
if (rawCaption.length === 0) rawCaption.push('-');
|
||||
|
||||
caption = rawCaption.join(' - ');
|
||||
|
||||
friendRawData.push({
|
||||
memberName: friend.MemberName,
|
||||
memberNumber: friend.MemberNumber,
|
||||
chatRoom: {
|
||||
name: originalChatRoomName,
|
||||
caption: caption,
|
||||
caption: chatRoomName || "-",
|
||||
canSearchRoom: canSearchRoom,
|
||||
types: [
|
||||
chatRoomSpaceCaption && chatRoomName ? FriendListIconMapping[friend.ChatRoomSpace ?? ""] : null,
|
||||
friend.Private ? FriendListIconMapping.Private : null,
|
||||
].filter(Boolean),
|
||||
},
|
||||
beep: {
|
||||
canBeep: canBeep,
|
||||
|
@ -653,18 +685,9 @@ function FriendListLoadFriendList(data) {
|
|||
const beepData = FriendListBeepLog[i];
|
||||
const chatRoomSpaceCaption = InterfaceTextGet(`ChatRoomSpace${beepData.ChatRoomSpace || "F"}`);
|
||||
const chatRoomName = ChatSearchMuffle(beepData.ChatRoomName?.replaceAll('<', '<').replaceAll('>', '>') || undefined);
|
||||
let chatRoomCaption = '';
|
||||
let beepCaption = '';
|
||||
const canSearchRoom = FriendListReturn?.Screen === 'ChatSearch' && ChatRoomSpace === (beepData.ChatRoomSpace || '');
|
||||
|
||||
const rawRoomCaption = [];
|
||||
if (chatRoomSpaceCaption && chatRoomName) rawRoomCaption.push(`<i>${chatRoomSpaceCaption}</i>`);
|
||||
if (beepData.Private) rawRoomCaption.push(PrivateRoomCaption);
|
||||
if (chatRoomName) rawRoomCaption.push(chatRoomName);
|
||||
if (rawRoomCaption.length === 0) rawRoomCaption.push('-');
|
||||
|
||||
chatRoomCaption = rawRoomCaption.join(' - ');
|
||||
|
||||
const rawBeepCaption = [];
|
||||
if (beepData.Sent) {
|
||||
rawBeepCaption.push(SentCaption);
|
||||
|
@ -683,8 +706,12 @@ function FriendListLoadFriendList(data) {
|
|||
memberNumber: beepData.MemberNumber,
|
||||
chatRoom: {
|
||||
name: beepData.ChatRoomName,
|
||||
caption: chatRoomCaption,
|
||||
caption: chatRoomName || "-",
|
||||
canSearchRoom: canSearchRoom,
|
||||
types: [
|
||||
chatRoomSpaceCaption && chatRoomName ? FriendListIconMapping[beepData.ChatRoomSpace ?? ""] : null,
|
||||
beepData.Private ? FriendListIconMapping.Private : null,
|
||||
].filter(Boolean),
|
||||
},
|
||||
beep: {
|
||||
beepIndex: i,
|
||||
|
@ -718,18 +745,18 @@ function FriendListLoadFriendList(data) {
|
|||
|
||||
friendRawData.forEach(friend => {
|
||||
const row = ElementCreate({
|
||||
tag: "div",
|
||||
tag: "tr",
|
||||
classList: ['friend-list-row'],
|
||||
children: [
|
||||
{
|
||||
tag: "span",
|
||||
tag: "td",
|
||||
classList: ['friend-list-column', 'MemberName'],
|
||||
children: [
|
||||
friend.memberName
|
||||
],
|
||||
},
|
||||
{
|
||||
tag: "span",
|
||||
tag: "td",
|
||||
classList: ['friend-list-column', 'MemberNumber'],
|
||||
children: [
|
||||
friend.memberNumber.toString()
|
||||
|
@ -740,20 +767,96 @@ function FriendListLoadFriendList(data) {
|
|||
|
||||
if (friend.chatRoom) {
|
||||
if (!friend.chatRoom.name || !friend.chatRoom.canSearchRoom) {
|
||||
row.appendChild(ElementCreate({
|
||||
tag: "span",
|
||||
classList: ['friend-list-column', 'ChatRoomName'],
|
||||
innerHTML: friend.chatRoom.caption,
|
||||
}));
|
||||
// Sorting is performed via each cell's `textContent`,
|
||||
// so explicitly prepend an invisible node with some sorting key
|
||||
let totalSortKey = "";
|
||||
const imgContainer = ElementCreate({
|
||||
tag: "td",
|
||||
classList: ['friend-list-column', 'ChatRoomType'],
|
||||
children: [
|
||||
{ tag: "span", style: { display: "none" }, classList: ["friend-list-sorting-node"] },
|
||||
...friend.chatRoom.types.map(({ src, tooltipKey, sortKey }) => {
|
||||
totalSortKey += sortKey;
|
||||
return {
|
||||
tag: /** @type {const} */("div"),
|
||||
classList: ["friend-list-icon-container"],
|
||||
children: [
|
||||
{
|
||||
tag: /** @type {const} */("img"),
|
||||
attributes: { src, decoding: "async", loading: "lazy", alt: TextGet(tooltipKey) },
|
||||
classList: ["friend-list-icon"],
|
||||
},
|
||||
{
|
||||
tag: /** @type {const} */("div"),
|
||||
attributes: { role: "tooltip", "aria-hidden": "true" },
|
||||
children: [TextGet(tooltipKey)],
|
||||
classList: ["button-tooltip", "button-tooltip-right"],
|
||||
},
|
||||
],
|
||||
};
|
||||
}),
|
||||
],
|
||||
});
|
||||
imgContainer.children[0].textContent = totalSortKey + " ";
|
||||
if (imgContainer.children.length === 1) {
|
||||
imgContainer.append("-");
|
||||
}
|
||||
row.append(
|
||||
imgContainer,
|
||||
ElementCreate({
|
||||
tag: "td",
|
||||
classList: ['friend-list-column', 'ChatRoomName'],
|
||||
children: [friend.chatRoom.caption],
|
||||
style: { "user-select": friend.chatRoom.caption === "-" ? "none" : undefined },
|
||||
}),
|
||||
);
|
||||
} else if (friend.chatRoom.canSearchRoom) {
|
||||
row.appendChild(ElementCreate({
|
||||
tag: "button",
|
||||
classList: ['friend-list-column', 'friend-list-link', 'blank-button', 'ChatRoomName'],
|
||||
innerHTML: friend.chatRoom.caption,
|
||||
eventListeners: {
|
||||
click: () => FriendListChatSearch(friend.chatRoom.name),
|
||||
},
|
||||
}));
|
||||
// Sorting is performed via each cell's `textContent`,
|
||||
// so explicitly prepend an invisible node with some sorting key
|
||||
let totalSortKey = "";
|
||||
const imgContainer = ElementCreate({
|
||||
tag: "td",
|
||||
classList: ['friend-list-column', 'ChatRoomType'],
|
||||
children: [
|
||||
{ tag: "span", style: { display: "none" }, classList: ["friend-list-sorting-node"] },
|
||||
...friend.chatRoom.types.map(({ src, tooltipKey, sortKey }) => {
|
||||
totalSortKey += sortKey;
|
||||
return {
|
||||
tag: /** @type {const} */("div"),
|
||||
classList: ["friend-list-icon-container"],
|
||||
children: [
|
||||
{
|
||||
tag: /** @type {const} */("img"),
|
||||
attributes: { src, decoding: "async", loading: "lazy", alt: TextGet(tooltipKey) },
|
||||
classList: ["friend-list-icon"],
|
||||
},
|
||||
{
|
||||
tag: /** @type {const} */("div"),
|
||||
attributes: { role: "tooltip", "aria-hidden": "true" },
|
||||
children: [TextGet(tooltipKey)],
|
||||
classList: ["button-tooltip", "button-tooltip-right"],
|
||||
},
|
||||
],
|
||||
};
|
||||
}),
|
||||
],
|
||||
});
|
||||
imgContainer.children[0].textContent = totalSortKey + " ";
|
||||
if (imgContainer.children.length === 1) {
|
||||
imgContainer.append("-");
|
||||
}
|
||||
row.append(
|
||||
imgContainer,
|
||||
ElementCreate({
|
||||
tag: "td",
|
||||
classList: ['friend-list-column', 'friend-list-link', 'blank-button', 'ChatRoomName'],
|
||||
innerHTML: friend.chatRoom.caption,
|
||||
style: { "user-select": friend.chatRoom.caption === "-" ? "none" : undefined },
|
||||
eventListeners: {
|
||||
click: () => FriendListChatSearch(friend.chatRoom.name),
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -767,6 +870,7 @@ function FriendListLoadFriendList(data) {
|
|||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-online-friends-content'],
|
||||
children: [friend.beep.caption],
|
||||
attributes: { role: "cell" },
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
|
@ -776,12 +880,13 @@ function FriendListLoadFriendList(data) {
|
|||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-beeps-content'],
|
||||
children: [friend.beep.caption],
|
||||
attributes: { role: "cell" },
|
||||
}},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
row.appendChild(ElementCreate({
|
||||
tag: "span",
|
||||
tag: "td",
|
||||
classList: ['friend-list-column'],
|
||||
children: [
|
||||
friend.beep.caption
|
||||
|
@ -792,14 +897,18 @@ function FriendListLoadFriendList(data) {
|
|||
|
||||
if (friend.relationType) {
|
||||
row.appendChild(ElementCreate({
|
||||
tag: "span",
|
||||
tag: "td",
|
||||
classList: ['friend-list-column', 'RelationType', 'mode-specific-content', 'fl-all-friends-content'],
|
||||
children: [
|
||||
{
|
||||
tag: 'img',
|
||||
tag: "img",
|
||||
attributes: {
|
||||
src: relationTypeIcons[friend.relationType],
|
||||
}
|
||||
decoding: "async",
|
||||
loading: "lazy",
|
||||
"aria-hidden": "true",
|
||||
},
|
||||
classList: ["friend-list-icon-small"],
|
||||
},
|
||||
FriendTypeCaption[friend.relationType]
|
||||
],
|
||||
|
@ -813,7 +922,7 @@ function FriendListLoadFriendList(data) {
|
|||
{ button: {
|
||||
classList: ['friend-list-column', 'friend-list-link', 'mode-specific-content', 'fl-all-friends-content'],
|
||||
children: [FriendListConfirmDelete.includes(friend.memberNumber) ? ConfirmDeleteCaption : DeleteCaption],
|
||||
attributes: { disabled: !friend.canDelete },
|
||||
attributes: { disabled: !friend.canDelete, role: "cell" },
|
||||
}}
|
||||
));
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ MemberName,Name
|
|||
MemberNickname,Nickname
|
||||
MemberNumber,Member number
|
||||
ChatRoomName,Chat room
|
||||
FriendType,Relation type
|
||||
ChatRoomType,Room type
|
||||
RelationType,Relation type
|
||||
ActionFriends,Send a Beep
|
||||
ActionRead,Read a Beep
|
||||
ActionDelete,Delete a Friend
|
||||
|
@ -21,3 +22,8 @@ TypeOwner,Owner
|
|||
TypeLover,Lover
|
||||
TypeSubmissive,Submissive
|
||||
TypeFriend,Friend
|
||||
TypeFemale,Femaly-only room
|
||||
TypeMale,Male-only room
|
||||
TypeMixed,Mixed male/female room
|
||||
TypeAsylum,Asylum room
|
||||
TypePrivate,Private room
|
||||
|
|
|
2
BondageClub/Scripts/Typedef.d.ts
vendored
2
BondageClub/Scripts/Typedef.d.ts
vendored
|
@ -901,7 +901,7 @@ interface IFriendListBeepLogMessage {
|
|||
MemberName: string;
|
||||
ChatRoomName?: string;
|
||||
Private: boolean;
|
||||
ChatRoomSpace?: string;
|
||||
ChatRoomSpace?: ServerChatRoomSpace;
|
||||
Sent: boolean;
|
||||
Time: Date;
|
||||
Message?: string;
|
||||
|
|
Loading…
Add table
Reference in a new issue