mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-14 02:55:47 +05:00
build: modernize WebUI build and lint tooling
This commit is contained in:
parent
f0cb7e1c83
commit
35c5c17309
@ -1,57 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"commonjs": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly",
|
||||
"window": "readonly",
|
||||
"document": "readonly"
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"ignorePatterns": ["mithril.js", "assets/*", "make-src/*"],
|
||||
"rules": {
|
||||
"linebreak-style": ["off", "unix"],
|
||||
"quotes": ["error", "single"],
|
||||
"semi": ["error", "always"],
|
||||
"arrow-spacing": ["error", { "before": true, "after": true }],
|
||||
"arrow-parens": ["error", "always"],
|
||||
"comma-style": ["error", "last"],
|
||||
"comma-spacing": ["error", { "before": false, "after": true }],
|
||||
"camelcase": [
|
||||
"error",
|
||||
{
|
||||
"allow": ["^UNSAFE_"],
|
||||
"properties": "never",
|
||||
"ignoreGlobals": true
|
||||
}
|
||||
],
|
||||
"eol-last": "error",
|
||||
"eqeqeq": ["error", "always", { "null": "ignore" }],
|
||||
"no-irregular-whitespace": ["error"],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-unexpected-multiline": ["error"],
|
||||
"no-unreachable": ["error"],
|
||||
"no-var": "warn",
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"args": "none",
|
||||
"caughtErrors": "none",
|
||||
"ignoreRestSiblings": true,
|
||||
"vars": "all"
|
||||
}
|
||||
],
|
||||
"no-use-before-define": ["warn", { "functions": true, "classes": false }],
|
||||
"object-shorthand": "error",
|
||||
"prefer-const": ["error", { "destructuring": "all" }],
|
||||
"semi-style": ["warn", "last"],
|
||||
"spaced-comment": ["warn", "always"]
|
||||
}
|
||||
}
|
||||
1
webui-src/.nvmrc
Normal file
1
webui-src/.nvmrc
Normal file
@ -0,0 +1 @@
|
||||
v24.15.0
|
||||
@ -39,7 +39,7 @@ function createboard() {
|
||||
m('label[for=thumbnail]', 'Thumbnail: '),
|
||||
m('input[type=file][name=files][id=thumbnail][accept=image/*]', {
|
||||
onchange: async (e) => {
|
||||
let reader = new FileReader();
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
thumbnail = reader.result.substring(reader.result.indexOf(',') + 1);
|
||||
};
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
|
||||
const GROUP_SUBSCRIBE_ADMIN = 0x01;// means: you have the admin key for this group
|
||||
const GROUP_SUBSCRIBE_PUBLISH = 0x02;// means: you have the publish key for thiss group. Typical use: publish key in channels are shared with specific friends.
|
||||
const GROUP_SUBSCRIBE_SUBSCRIBED = 0x04;// means: you are subscribed to a group, which makes you a source for this group to your friend nodes.
|
||||
const GROUP_SUBSCRIBE_ADMIN = 0x01; // means: you have the admin key for this group
|
||||
const GROUP_SUBSCRIBE_PUBLISH = 0x02; // means: you have the publish key for thiss group. Typical use: publish key in channels are shared with specific friends.
|
||||
const GROUP_SUBSCRIBE_SUBSCRIBED = 0x04; // means: you are subscribed to a group, which makes you a source for this group to your friend nodes.
|
||||
const GROUP_SUBSCRIBE_NOT_SUBSCRIBED = 0x08;
|
||||
const GROUP_MY_BOARD = GROUP_SUBSCRIBE_ADMIN + GROUP_SUBSCRIBE_SUBSCRIBED + GROUP_SUBSCRIBE_PUBLISH;
|
||||
const GXS_VOTE_DOWN = 0x0001;
|
||||
const GXS_VOTE_UP = 0x0002;
|
||||
|
||||
//rsgxscircles.h:50
|
||||
const PUBLIC = 1; /// Public distribution
|
||||
const EXTERNAL = 2; /// Restricted to an external circle, based on GxsIds
|
||||
// rsgxscircles.h:50
|
||||
const PUBLIC = 1; // Public distribution
|
||||
const EXTERNAL = 2; // Restricted to an external circle, based on GxsIds
|
||||
const NODES_GROUP = 3;
|
||||
|
||||
const Data = {
|
||||
@ -20,34 +20,6 @@ const Data = {
|
||||
Comments: {}, // threadID, msgID -> {Comment, showReplies}
|
||||
};
|
||||
|
||||
async function updateContent(content, boardid) {
|
||||
const res = await rs.rsJsonApiRequest('/rsPosted/getBoardContent', {
|
||||
boardId: boardid,
|
||||
contentsIds: [content.mMsgId],
|
||||
});
|
||||
if (res.body.retval && res.body.posts.length > 0) {
|
||||
Data.Posts[boardid][content.mMsgId] = { post: res.body.posts[0], isSearched: true };
|
||||
} else if (res.body.retval && res.body.comments.length > 0) {
|
||||
if (Data.Comments[content.mThreadId] === undefined) {
|
||||
Data.Comments[content.mThreadId] = {};
|
||||
}
|
||||
Data.Comments[content.mThreadId][content.mMsgId] = res.body.comments[0];
|
||||
} else if (res.body.retval && res.body.votes.length > 0) {
|
||||
const vote = res.body.votes[0];
|
||||
if (
|
||||
Data.Comments[vote.mMeta.mThreadId] &&
|
||||
Data.Comments[vote.mMeta.mThreadId][vote.mMeta.mParentId]
|
||||
) {
|
||||
if (vote.mVoteType === GXS_VOTE_UP) {
|
||||
Data.Comments[vote.mMeta.mThreadId][vote.mMeta.mParentId].mUpVotes += 1;
|
||||
}
|
||||
if (vote.mVoteType === GXS_VOTE_DOWN) {
|
||||
Data.Comments[vote.mMeta.mThreadId][vote.mMeta.mParentId].mDownVotes += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateDisplayBoards(keyid, details) {
|
||||
const res1 = await rs.rsJsonApiRequest('/rsPosted/getBoardsInfo', {
|
||||
boardsIds: [keyid],
|
||||
@ -72,7 +44,7 @@ async function updateDisplayBoards(keyid, details) {
|
||||
Data.Posts[keyid] = {};
|
||||
}
|
||||
|
||||
/*const res2 = await rs.rsJsonApiRequest('/rsPosted/getContentSummaries', {
|
||||
/* const res2 = await rs.rsJsonApiRequest('/rsPosted/getContentSummaries', {
|
||||
boardId: keyid,
|
||||
});
|
||||
|
||||
@ -81,7 +53,6 @@ async function updateDisplayBoards(keyid, details) {
|
||||
updateContent(content, keyid);
|
||||
});
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
const DisplayBoardsFromList = () => {
|
||||
|
||||
@ -109,7 +109,7 @@ function createchannel() {
|
||||
m('label[for=thumbnail]', 'Thumbnail: '),
|
||||
m('input[type=file][name=files][id=thumbnail][accept=image/*]', {
|
||||
onchange: async (e) => {
|
||||
let reader = new FileReader();
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
thumbnail = reader.result.substring(reader.result.indexOf(',') + 1);
|
||||
};
|
||||
@ -238,7 +238,7 @@ const AddPost = () => {
|
||||
m('label[for=thumbnail]', 'Thumbnail: '),
|
||||
m('input[type=file][name=files][id=thumbnail][accept=image/*]', {
|
||||
onchange: async (e) => {
|
||||
let reader = new FileReader();
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
pthumbnail = reader.result.substring(reader.result.indexOf(',') + 1);
|
||||
};
|
||||
|
||||
@ -7,18 +7,11 @@ const chatEmoji = require('chat/chat_emoji');
|
||||
const HistoryBrowserModal = require('people/people_history');
|
||||
|
||||
const {
|
||||
get64Num,
|
||||
loadLobbyDetails,
|
||||
loadDistantChatDetails,
|
||||
sortLobbies,
|
||||
getNicknameColor,
|
||||
getStatusColor,
|
||||
getStatusTooltip,
|
||||
renderTextWithEmoji,
|
||||
getSafeAvatar,
|
||||
MobileState,
|
||||
ChatRoomsModel,
|
||||
Message,
|
||||
ChatLobbyModel,
|
||||
ChatHubState,
|
||||
} = chatState;
|
||||
@ -123,13 +116,13 @@ function pollHashStatus(localpath) {
|
||||
const info = data.info;
|
||||
const sizeNum = info.size.xint64 || parseInt(info.size.xstr64) || info.size;
|
||||
const fileLink = `<a href="retroshare://file?name=${encodeURIComponent(info.name)}&size=${sizeNum}&hash=${info.hash}">${info.name}</a> (${rs.formatBytes(sizeNum)})`;
|
||||
|
||||
|
||||
const textarea = document.querySelector('.chat-hub-textarea');
|
||||
if (textarea) {
|
||||
const val = textarea.value;
|
||||
textarea.value = val ? val + '\n' + fileLink : fileLink;
|
||||
}
|
||||
|
||||
|
||||
ChatHubState.showAttachModal = false;
|
||||
ChatHubState.isHashing = false;
|
||||
ChatHubState.attachPath = '';
|
||||
@ -144,75 +137,6 @@ function pollHashStatus(localpath) {
|
||||
|
||||
// ************************* views ****************************
|
||||
|
||||
const Lobby = () => {
|
||||
return {
|
||||
view: (vnode) => {
|
||||
const { info, tagname, onclick, lobbytagname = 'mainname' } = vnode.attrs;
|
||||
return m(
|
||||
ChatLobbyModel.selected(info, '.selected-lobby', tagname),
|
||||
{
|
||||
key: rs.idToHex(info.lobby_id),
|
||||
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 [
|
||||
vnode.attrs.rooms.map((info) =>
|
||||
m(Lobby, {
|
||||
info,
|
||||
tagname,
|
||||
lobbytagname,
|
||||
onclick: onclick(info),
|
||||
})
|
||||
),
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
const SubscribedLobbies = {
|
||||
view() {
|
||||
return m('.widget', [
|
||||
m('.widget__heading', m('h3', 'Subscribed chat rooms')),
|
||||
m('.widget__body', [
|
||||
m(LobbyList, {
|
||||
rooms: sortLobbies(Object.values(ChatRoomsModel.subscribedRooms)),
|
||||
tagname: '.lobby.subscribed',
|
||||
onclick: ChatLobbyModel.switchToEvent,
|
||||
}),
|
||||
]),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
const PublicLobbies = {
|
||||
view() {
|
||||
return m('.widget', [
|
||||
m('.widget__heading', m('h3', 'Public chat rooms')),
|
||||
m('.widget__body', [
|
||||
m(LobbyList, {
|
||||
rooms: (ChatRoomsModel.allRooms || []).filter((info) => !ChatRoomsModel.subscribed(info)),
|
||||
tagname: '.lobby.public',
|
||||
onclick: ChatLobbyModel.setupEvent,
|
||||
}),
|
||||
]),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
// ************************* Chat Hub Sub-Components ****************************
|
||||
|
||||
const ChatRoomHeader = () => {
|
||||
return {
|
||||
view: (vnode) => {
|
||||
@ -982,8 +906,6 @@ const ChatRoomDetailView = () => {
|
||||
const room = ChatHubState.selectedRoom;
|
||||
if (!room) return null;
|
||||
|
||||
let participantCount = 0;
|
||||
let participantNames = [];
|
||||
let participants = [];
|
||||
|
||||
if (room.gxs_ids) {
|
||||
@ -994,7 +916,7 @@ const ChatRoomDetailView = () => {
|
||||
}));
|
||||
} else if (typeof room.gxs_ids === 'object') {
|
||||
participants = Object.keys(room.gxs_ids).map((key) => ({
|
||||
key: key,
|
||||
key,
|
||||
name: rs.userList.username(key) || key
|
||||
}));
|
||||
}
|
||||
@ -1011,8 +933,8 @@ const ChatRoomDetailView = () => {
|
||||
}
|
||||
}
|
||||
|
||||
participantCount = participants.length;
|
||||
participantNames = participants.map((p) => p.name);
|
||||
const participantCount = participants.length;
|
||||
const participantNames = participants.map((p) => p.name);
|
||||
participantNames.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
const lobbyHexId = rs.idToHex(room.lobby_id);
|
||||
@ -1316,7 +1238,7 @@ const Layout = {
|
||||
ChatHubState.showCreateRoomModal && m('.attach-modal-overlay', [
|
||||
m('.attach-modal', [
|
||||
m('h4', 'Create New Chat Room'),
|
||||
|
||||
|
||||
m('.form-field', { style: 'display: flex; flex-direction: column; gap: 0.25rem;' }, [
|
||||
m('label', { style: 'font-weight: bold; font-size: 0.9rem; color: #475569;' }, 'Room Name:'),
|
||||
m('input[type=text]', {
|
||||
@ -1326,7 +1248,7 @@ const Layout = {
|
||||
style: 'padding: 0.5rem; border: 1px solid #cbd5e1; border-radius: 0.25rem; font-size: 0.9rem;'
|
||||
})
|
||||
]),
|
||||
|
||||
|
||||
m('.form-field', { style: 'display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.5rem;' }, [
|
||||
m('label', { style: 'font-weight: bold; font-size: 0.9rem; color: #475569;' }, 'Topic:'),
|
||||
m('input[type=text]', {
|
||||
@ -1344,7 +1266,7 @@ const Layout = {
|
||||
onchange: (e) => { ChatHubState.newRoomIdentity = e.target.value; },
|
||||
style: 'padding: 0.5rem; border: 1px solid #cbd5e1; border-radius: 0.25rem; font-size: 0.9rem; background-color: #ffffff;'
|
||||
}, [
|
||||
ChatHubState.ownGxsIdentities && ChatHubState.ownGxsIdentities.map(id => {
|
||||
ChatHubState.ownGxsIdentities && ChatHubState.ownGxsIdentities.map((id) => {
|
||||
const details = ChatHubState.gxsDetails[id];
|
||||
const name = details ? (details.mNickname || details.mGroupName) : id;
|
||||
return m('option', { value: id }, name);
|
||||
@ -1386,7 +1308,7 @@ const Layout = {
|
||||
let flags = 0;
|
||||
if (isPublic) flags |= 4;
|
||||
if (isSigned) flags |= 8;
|
||||
|
||||
|
||||
rs.rsJsonApiRequest('/rsChats/createChatLobby', {
|
||||
lobby_name: name,
|
||||
lobby_identity: identity,
|
||||
@ -1601,74 +1523,6 @@ const Layout = {
|
||||
},
|
||||
};
|
||||
|
||||
const LayoutSingle = () => {
|
||||
const onResize = () => {
|
||||
const element = document.querySelector('.messages');
|
||||
if (element) element.scrollTop = element.scrollHeight;
|
||||
};
|
||||
return {
|
||||
oninit: () => {
|
||||
ChatLobbyModel.loadLobby(m.route.param('lobby'));
|
||||
window.addEventListener('resize', onResize);
|
||||
},
|
||||
onremove: () => window.removeEventListener('resize', onResize),
|
||||
view: (vnode) => {
|
||||
const chatType = ChatLobbyModel.currentLobby.chatType;
|
||||
const isPrivate = chatType === 1 || chatType === 2;
|
||||
const isRoom = chatType === 3;
|
||||
return m(
|
||||
'.node-panel.chat-panel.chat-room',
|
||||
{
|
||||
class:
|
||||
(MobileState.showLobbies ? 'show-lobbies ' : '') +
|
||||
(MobileState.showUsers ? 'show-users ' : '') +
|
||||
(isPrivate ? 'no-lobbies' : ''),
|
||||
},
|
||||
[
|
||||
m('.chat-overlay', { onclick: () => MobileState.closeAll() }),
|
||||
m(
|
||||
'.messages' + (isRoom ? '.compact-container' : ''),
|
||||
{ onclick: () => MobileState.closeAll() },
|
||||
ChatLobbyModel.messages
|
||||
),
|
||||
m(
|
||||
'.chatMessage',
|
||||
{},
|
||||
[
|
||||
m('textarea.chatMsg', {
|
||||
placeholder: 'Type a message...',
|
||||
enterkeyhint: 'send',
|
||||
onkeydown: (e) => {
|
||||
if ((e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey) {
|
||||
const msg = e.target.value;
|
||||
if (msg.trim() === '') return false;
|
||||
e.target.value = ' sending ... ';
|
||||
ChatLobbyModel.sendMessage(msg, () => (e.target.value = ''));
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}),
|
||||
m(
|
||||
'button.chat-send-btn',
|
||||
{
|
||||
onclick: (e) => {
|
||||
const textarea = e.target.closest('.chatMessage').querySelector('textarea');
|
||||
const msg = textarea.value;
|
||||
if (msg.trim() === '') return;
|
||||
textarea.value = ' sending ... ';
|
||||
ChatLobbyModel.sendMessage(msg, () => (textarea.value = ''));
|
||||
},
|
||||
},
|
||||
m('i.fas.fa-paper-plane')
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
/rsChats/initiateDistantChatConnexion
|
||||
* @param[in] to_pid RsGxsId to start the connection
|
||||
|
||||
@ -7,72 +7,72 @@ const EMOJI_ICONS = {
|
||||
};
|
||||
const EMOJI_DATA = {
|
||||
Smileys: [
|
||||
'😀','😁','😂','🤣','😃','😄','😅','😆','😉','😊','😋','😎','😍','😘','🥰','😗','😙','😚',
|
||||
'🙂','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣','😥','😮','🤐','😯','😪','😫','🥱',
|
||||
'😴','😌','😛','😜','😝','🤤','😒','😓','😔','😕','🙃','🤑','😲','☹️','🙁','😖','😞','😟',
|
||||
'😤','😢','😭','😦','😧','😨','😩','🤯','😬','😰','😱','🥵','🥶','😳','🤪','😵','😡','😠',
|
||||
'🤬','😷','🤒','🤕','🤢','🤮','🤧','🥴','😇','🥳','🥺','🤠','🤡','🤥','🤫','🤭','🧐','🤓',
|
||||
'😈','👿','👹','👺','💀','☠️','👻','👽','👾','🤖','😺','😸','😹','😻','😼','😽','🙀','😿','😾',
|
||||
'😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆', '😉', '😊', '😋', '😎', '😍', '😘', '🥰', '😗', '😙', '😚',
|
||||
'🙂', '🤗', '🤩', '🤔', '🤨', '😐', '😑', '😶', '🙄', '😏', '😣', '😥', '😮', '🤐', '😯', '😪', '😫', '🥱',
|
||||
'😴', '😌', '😛', '😜', '😝', '🤤', '😒', '😓', '😔', '😕', '🙃', '🤑', '😲', '☹️', '🙁', '😖', '😞', '😟',
|
||||
'😤', '😢', '😭', '😦', '😧', '😨', '😩', '🤯', '😬', '😰', '😱', '🥵', '🥶', '😳', '🤪', '😵', '😡', '😠',
|
||||
'🤬', '😷', '🤒', '🤕', '🤢', '🤮', '🤧', '🥴', '😇', '🥳', '🥺', '🤠', '🤡', '🤥', '🤫', '🤭', '🧐', '🤓',
|
||||
'😈', '👿', '👹', '👺', '💀', '☠️', '👻', '👽', '👾', '🤖', '😺', '😸', '😹', '😻', '😼', '😽', '🙀', '😿', '😾',
|
||||
],
|
||||
People: [
|
||||
'👋','🤚','🖐️','✋','🖖','👌','🤌','🤏','✌️','🤞','🤟','🤘','🤙','👈','👉','👆','🖕','👇',
|
||||
'☝️','👍','👎','✊','👊','🤛','🤜','👏','🙌','👐','🤲','🤝','🙏','✍️','💅','🤳','💪','🦾',
|
||||
'🦿','🦵','🦶','👂','🦻','👃','🫀','🫁','🧠','🦷','🦴','👀','👁️','👅','👄','🫦','👶','🧒',
|
||||
'👦','👧','🧑','👱','👨','🧔','👩','🧓','👴','👵','🙍','🙎','🙅','🙆','💁','🙋','🧏','🙇',
|
||||
'🤦','🤷','👮','🕵️','💂','🥷','👷','🫅','🤴','👸','👲','🧕','🤵','👰','🤰','🫃','🫄','🤱',
|
||||
'👼','🎅','🤶','🧑🎄','🦸','🦹','🧙','🧝','🧛','🧟','🧞','🧜','🧚','🧑🤝🧑','👫','👬','👭','💏','💑','👪',
|
||||
'👋', '🤚', '🖐️', '✋', '🖖', '👌', '🤌', '🤏', '✌️', '🤞', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇',
|
||||
'☝️', '👍', '👎', '✊', '👊', '🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✍️', '💅', '🤳', '💪', '🦾',
|
||||
'🦿', '🦵', '🦶', '👂', '🦻', '👃', '🫀', '🫁', '🧠', '🦷', '🦴', '👀', '👁️', '👅', '👄', '🫦', '👶', '🧒',
|
||||
'👦', '👧', '🧑', '👱', '👨', '🧔', '👩', '🧓', '👴', '👵', '🙍', '🙎', '🙅', '🙆', '💁', '🙋', '🧏', '🙇',
|
||||
'🤦', '🤷', '👮', '🕵️', '💂', '🥷', '👷', '🫅', '🤴', '👸', '👲', '🧕', '🤵', '👰', '🤰', '🫃', '🫄', '🤱',
|
||||
'👼', '🎅', '🤶', '🧑🎄', '🦸', '🦹', '🧙', '🧝', '🧛', '🧟', '🧞', '🧜', '🧚', '🧑🤝🧑', '👫', '👬', '👭', '💏', '💑', '👪',
|
||||
],
|
||||
Animals: [
|
||||
'🐶','🐱','🐭','🐹','🐰','🦊','🐻','🐼','🐻❄️','🐨','🐯','🦁','🐮','🐷','🐸','🐵','🙈','🙉',
|
||||
'🙊','🐒','🦆','🦅','🦉','🦇','🐝','🪱','🐛','🦋','🐌','🐞','🐜','🪲','🦗','🪳','🕷️','🦂',
|
||||
'🐢','🐍','🦎','🦖','🦕','🐙','🦑','🦐','🦞','🦀','🐡','🐠','🐟','🐬','🐳','🐋','🦈','🦭',
|
||||
'🐊','🐅','🐆','🦓','🦍','🦧','🦣','🐘','🦛','🦏','🐪','🐫','🦒','🦘','🦬','🐃','🐂','🐄',
|
||||
'🐎','🐖','🐏','🐑','🦙','🐐','🦌','🐕','🐩','🦮','🐕🦺','🐈','🐈⬛','🐓','🦃','🦤','🦚','🦜',
|
||||
'🦢','🦩','🕊️','🐇','🦝','🦨','🦡','🦫','🦦','🦥','🐁','🐀','🐿️','🦔','🐾','🐉','🐲','🌵',
|
||||
'🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐻❄️', '🐨', '🐯', '🦁', '🐮', '🐷', '🐸', '🐵', '🙈', '🙉',
|
||||
'🙊', '🐒', '🦆', '🦅', '🦉', '🦇', '🐝', '🪱', '🐛', '🦋', '🐌', '🐞', '🐜', '🪲', '🦗', '🪳', '🕷️', '🦂',
|
||||
'🐢', '🐍', '🦎', '🦖', '🦕', '🐙', '🦑', '🦐', '🦞', '🦀', '🐡', '🐠', '🐟', '🐬', '🐳', '🐋', '🦈', '🦭',
|
||||
'🐊', '🐅', '🐆', '🦓', '🦍', '🦧', '🦣', '🐘', '🦛', '🦏', '🐪', '🐫', '🦒', '🦘', '🦬', '🐃', '🐂', '🐄',
|
||||
'🐎', '🐖', '🐏', '🐑', '🦙', '🐐', '🦌', '🐕', '🐩', '🦮', '🐕🦺', '🐈', '🐈⬛', '🐓', '🦃', '🦤', '🦚', '🦜',
|
||||
'🦢', '🦩', '🕊️', '🐇', '🦝', '🦨', '🦡', '🦫', '🦦', '🦥', '🐁', '🐀', '🐿️', '🦔', '🐾', '🐉', '🐲', '🌵',
|
||||
],
|
||||
Food: [
|
||||
'🍎','🍊','🍋','🍌','🍍','🥭','🍓','🍒','🍑','🥝','🍅','🥥','🥑','🍆','🥔','🥕','🌽','🌶️',
|
||||
'🫑','🥒','🥬','🥦','🧄','🧅','🍄','🥜','🌰','🍞','🥐','🥖','🫓','🥨','🧀','🥚','🍳','🧈',
|
||||
'🥞','🧇','🥓','🥩','🍗','🍖','🦴','🌭','🍔','🍟','🍕','🫔','🌮','🌯','🥙','🧆','🥚','🍱',
|
||||
'🍘','🍙','🍚','🍛','🍜','🍝','🍠','🍢','🍣','🍤','🍥','🥮','🍡','🥟','🥠','🥡','🦪','🍦',
|
||||
'🍧','🍨','🍩','🍪','🎂','🍰','🧁','🥧','🍫','🍬','🍭','🍮','🍯','🍼','🥛','☕','🫖','🍵',
|
||||
'🧃','🥤','🧋','🍶','🍺','🍻','🥂','🍷','🥃','🍸','🍹','🧉','🍾','🧊','🥄','🍴','🍽️','🥢',
|
||||
'🍎', '🍊', '🍋', '🍌', '🍍', '🥭', '🍓', '🍒', '🍑', '🥝', '🍅', '🥥', '🥑', '🍆', '🥔', '🥕', '🌽', '🌶️',
|
||||
'🫑', '🥒', '🥬', '🥦', '🧄', '🧅', '🍄', '🥜', '🌰', '🍞', '🥐', '🥖', '🫓', '🥨', '🧀', '🥚', '🍳', '🧈',
|
||||
'🥞', '🧇', '🥓', '🥩', '🍗', '🍖', '🦴', '🌭', '🍔', '🍟', '🍕', '🫔', '🌮', '🌯', '🥙', '🧆', '🥚', '🍱',
|
||||
'🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍠', '🍢', '🍣', '🍤', '🍥', '🥮', '🍡', '🥟', '🥠', '🥡', '🦪', '🍦',
|
||||
'🍧', '🍨', '🍩', '🍪', '🎂', '🍰', '🧁', '🥧', '🍫', '🍬', '🍭', '🍮', '🍯', '🍼', '🥛', '☕', '🫖', '🍵',
|
||||
'🧃', '🥤', '🧋', '🍶', '🍺', '🍻', '🥂', '🍷', '🥃', '🍸', '🍹', '🧉', '🍾', '🧊', '🥄', '🍴', '🍽️', '🥢',
|
||||
],
|
||||
Travel: [
|
||||
'🚗','🚕','🚙','🚌','🚎','🏎️','🚓','🚑','🚒','🚐','🛻','🚚','🚛','🚜','🦯','🦽','🦼','🛺',
|
||||
'🚲','🛴','🛵','🏍️','🛺','🚨','🚔','🚍','🚘','🚖','🚡','🚠','🚟','🚃','🚋','🚞','🚝','🚄',
|
||||
'🚅','🚈','🚂','🚆','🚇','🚊','🚉','✈️','🛫','🛬','🛩️','💺','🛸','🚁','🛶','⛵','🚤','🛥️',
|
||||
'🛳️','⛴️','🚢','⚓','🗺️','🧭','🏔️','⛰️','🌋','🗻','🏕️','🏖️','🏜️','🏝️','🏞️','🏟️','🏛️','🏗️',
|
||||
'🧱','🪨','🪵','🛖','🏘️','🏚️','🏠','🏡','🏢','🏣','🏤','🏥','🏦','🏨','🏩','🏪','🏫','🏬',
|
||||
'🏭','🏯','🏰','💒','🗼','🗽','⛪','🕌','🛕','🕍','⛩️','🕋','⛲','⛺','🌁','🌃','🏙️','🌄',
|
||||
'🚗', '🚕', '🚙', '🚌', '🚎', '🏎️', '🚓', '🚑', '🚒', '🚐', '🛻', '🚚', '🚛', '🚜', '🦯', '🦽', '🦼', '🛺',
|
||||
'🚲', '🛴', '🛵', '🏍️', '🛺', '🚨', '🚔', '🚍', '🚘', '🚖', '🚡', '🚠', '🚟', '🚃', '🚋', '🚞', '🚝', '🚄',
|
||||
'🚅', '🚈', '🚂', '🚆', '🚇', '🚊', '🚉', '✈️', '🛫', '🛬', '🛩️', '💺', '🛸', '🚁', '🛶', '⛵', '🚤', '🛥️',
|
||||
'🛳️', '⛴️', '🚢', '⚓', '🗺️', '🧭', '🏔️', '⛰️', '🌋', '🗻', '🏕️', '🏖️', '🏜️', '🏝️', '🏞️', '🏟️', '🏛️', '🏗️',
|
||||
'🧱', '🪨', '🪵', '🛖', '🏘️', '🏚️', '🏠', '🏡', '🏢', '🏣', '🏤', '🏥', '🏦', '🏨', '🏩', '🏪', '🏫', '🏬',
|
||||
'🏭', '🏯', '🏰', '💒', '🗼', '🗽', '⛪', '🕌', '🛕', '🕍', '⛩️', '🕋', '⛲', '⛺', '🌁', '🌃', '🏙️', '🌄',
|
||||
],
|
||||
Activities: [
|
||||
'⚽','🏀','🏈','⚾','🥎','🎾','🏐','🏉','🥏','🎱','🏓','🏸','🏒','🏑','🥍','🏏','🪃','🥅',
|
||||
'⛳','🪁','🛝','🏹','🎣','🤿','🥊','🥋','🎽','🛹','🛷','⛸️','🥌','🎿','⛷️','🏂','🪂','🏋️',
|
||||
'🤼','🤸','⛹️','🤺','🏇','🧘','🏄','🏊','🤽','🚣','🧗','🚵','🚴','🏆','🥇','🥈','🥉','🏅',
|
||||
'🎖️','🏵️','🎗️','🎫','🎟️','🎪','🤹','🎭','🩰','🎨','🖼️','🎰','🎲','🧩','🪄','🎯','🪅','🎮',
|
||||
'🕹️','🎳','🎻','🎷','🥁','🪘','🎺','🎸','🪗','🎹','🎵','🎶','🎼','🎤','🎧','📻','🎙️','🎚️',
|
||||
'🎬','📽️','🎞️','📱','📲','☎️','📞','📟','📠','🔋','🪫','🔌','💡','🔦','🕯️','💸','💵','🪙',
|
||||
'⚽', '🏀', '🏈', '⚾', '🥎', '🎾', '🏐', '🏉', '🥏', '🎱', '🏓', '🏸', '🏒', '🏑', '🥍', '🏏', '🪃', '🥅',
|
||||
'⛳', '🪁', '🛝', '🏹', '🎣', '🤿', '🥊', '🥋', '🎽', '🛹', '🛷', '⛸️', '🥌', '🎿', '⛷️', '🏂', '🪂', '🏋️',
|
||||
'🤼', '🤸', '⛹️', '🤺', '🏇', '🧘', '🏄', '🏊', '🤽', '🚣', '🧗', '🚵', '🚴', '🏆', '🥇', '🥈', '🥉', '🏅',
|
||||
'🎖️', '🏵️', '🎗️', '🎫', '🎟️', '🎪', '🤹', '🎭', '🩰', '🎨', '🖼️', '🎰', '🎲', '🧩', '🪄', '🎯', '🪅', '🎮',
|
||||
'🕹️', '🎳', '🎻', '🎷', '🥁', '🪘', '🎺', '🎸', '🪗', '🎹', '🎵', '🎶', '🎼', '🎤', '🎧', '📻', '🎙️', '🎚️',
|
||||
'🎬', '📽️', '🎞️', '📱', '📲', '☎️', '📞', '📟', '📠', '🔋', '🪫', '🔌', '💡', '🔦', '🕯️', '💸', '💵', '🪙',
|
||||
],
|
||||
Objects: [
|
||||
'⌚','📱','📲','💻','⌨️','🖥️','🖨️','🖱️','🖲️','💾','💿','📀','🧮','📷','📸','📹','🎥','📽️',
|
||||
'📞','☎️','📟','📠','📺','📻','🧭','⏱️','⏲️','⏰','🕰️','⌛','⏳','📡','🔋','🪫','🔌','💡',
|
||||
'🔦','🕯️','🪔','🧱','💰','💴','💵','💶','💷','💸','💳','🪙','💹','✉️','📧','📨','📩','📤',
|
||||
'📥','📦','📫','📪','📬','📭','📮','🗳️','✏️','✒️','🖊️','🖋️','📝','📁','📂','🗂️','📅','📆',
|
||||
'🗒️','🗓️','📇','📈','📉','📊','📋','📌','📍','🗺️','📏','📐','✂️','🗃️','🗄️','🗑️','🔒','🔓',
|
||||
'🔏','🔐','🔑','🗝️','🔨','🪓','⛏️','⚒️','🛠️','🗡️','⚔️','🔫','🪃','🏹','🛡️','🪚','🔧','🪛',
|
||||
'⌚', '📱', '📲', '💻', '⌨️', '🖥️', '🖨️', '🖱️', '🖲️', '💾', '💿', '📀', '🧮', '📷', '📸', '📹', '🎥', '📽️',
|
||||
'📞', '☎️', '📟', '📠', '📺', '📻', '🧭', '⏱️', '⏲️', '⏰', '🕰️', '⌛', '⏳', '📡', '🔋', '🪫', '🔌', '💡',
|
||||
'🔦', '🕯️', '🪔', '🧱', '💰', '💴', '💵', '💶', '💷', '💸', '💳', '🪙', '💹', '✉️', '📧', '📨', '📩', '📤',
|
||||
'📥', '📦', '📫', '📪', '📬', '📭', '📮', '🗳️', '✏️', '✒️', '🖊️', '🖋️', '📝', '📁', '📂', '🗂️', '📅', '📆',
|
||||
'🗒️', '🗓️', '📇', '📈', '📉', '📊', '📋', '📌', '📍', '🗺️', '📏', '📐', '✂️', '🗃️', '🗄️', '🗑️', '🔒', '🔓',
|
||||
'🔏', '🔐', '🔑', '🗝️', '🔨', '🪓', '⛏️', '⚒️', '🛠️', '🗡️', '⚔️', '🔫', '🪃', '🏹', '🛡️', '🪚', '🔧', '🪛',
|
||||
],
|
||||
Symbols: [
|
||||
'❤️','🧡','💛','💚','💙','💜','🖤','🤍','🤎','💔','❣️','💕','💞','💓','💗','💖','💘','💝',
|
||||
'💟','☮️','✝️','☪️','🕉️','☸️','✡️','🔯','🕎','☯️','☦️','🛐','⛎','♈','♉','♊','♋','♌',
|
||||
'♍','♎','♏','♐','♑','♒','♓','🆔','⚛️','🉑','☢️','☣️','📴','📳','🈶','🈚','🈸','🈺',
|
||||
'🈷️','✴️','🆚','💮','🉐','㊙️','㊗️','🈴','🈵','🈹','🈲','🅰️','🅱️','🆎','🆑','🅾️','🆘',
|
||||
'❌','⭕','🛑','⛔','📛','🚫','💯','💢','♨️','🚷','🚯','🚳','🚱','🔞','📵','🚭','❗','❕',
|
||||
'❓','❔','‼️','⁉️','🔅','🔆','📶','🛜','📳','📴','🔱','📛','🔰','♻️','✅','🈯','💹','❎',
|
||||
'🌐','💠','Ⓜ️','🌀','💤','🏧','🚾','♿','🅿️','🛗','🈳','🈹','🚰','🔤','🔡','🔠','🆖','🆗',
|
||||
'🆙','🆒','🆕','🆓','🔟','📊','🔣','✔️','☑️','🔘','🔲','🔳','⬛','⬜','◼️','◻️','◾','◽',
|
||||
'▪️','▫️','🔶','🔷','🔸','🔹','🔺','🔻','💠','🔘','🔲','🔳','🏁','🚩','🎌','🏴','🏳️','⭐',
|
||||
'🌟','💫','✨','🌈','☀️','🌤️','⛅','🌥️','☁️','🌦️','🌧️','⛈️','🌩️','🌨️','❄️','☃️','⛄','🌬️',
|
||||
'❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝',
|
||||
'💟', '☮️', '✝️', '☪️', '🕉️', '☸️', '✡️', '🔯', '🕎', '☯️', '☦️', '🛐', '⛎', '♈', '♉', '♊', '♋', '♌',
|
||||
'♍', '♎', '♏', '♐', '♑', '♒', '♓', '🆔', '⚛️', '🉑', '☢️', '☣️', '📴', '📳', '🈶', '🈚', '🈸', '🈺',
|
||||
'🈷️', '✴️', '🆚', '💮', '🉐', '㊙️', '㊗️', '🈴', '🈵', '🈹', '🈲', '🅰️', '🅱️', '🆎', '🆑', '🅾️', '🆘',
|
||||
'❌', '⭕', '🛑', '⛔', '📛', '🚫', '💯', '💢', '♨️', '🚷', '🚯', '🚳', '🚱', '🔞', '📵', '🚭', '❗', '❕',
|
||||
'❓', '❔', '‼️', '⁉️', '🔅', '🔆', '📶', '🛜', '📳', '📴', '🔱', '📛', '🔰', '♻️', '✅', '🈯', '💹', '❎',
|
||||
'🌐', '💠', 'Ⓜ️', '🌀', '💤', '🏧', '🚾', '♿', '🅿️', '🛗', '🈳', '🈹', '🚰', '🔤', '🔡', '🔠', '🆖', '🆗',
|
||||
'🆙', '🆒', '🆕', '🆓', '🔟', '📊', '🔣', '✔️', '☑️', '🔘', '🔲', '🔳', '⬛', '⬜', '◼️', '◻️', '◾', '◽',
|
||||
'▪️', '▫️', '🔶', '🔷', '🔸', '🔹', '🔺', '🔻', '💠', '🔘', '🔲', '🔳', '🏁', '🚩', '🎌', '🏴', '🏳️', '⭐',
|
||||
'🌟', '💫', '✨', '🌈', '☀️', '🌤️', '⛅', '🌥️', '☁️', '🌦️', '🌧️', '⛈️', '🌩️', '🌨️', '❄️', '☃️', '⛄', '🌬️',
|
||||
],
|
||||
};
|
||||
|
||||
@ -115,14 +115,14 @@ const EmojiPicker = () => ({
|
||||
onclick: () => { ChatHubState.emojiSearch = ''; },
|
||||
}, m('i.fas.fa-times')),
|
||||
]),
|
||||
!search && m('.emoji-categories', EMOJI_CATEGORIES.map(c =>
|
||||
!search && m('.emoji-categories', EMOJI_CATEGORIES.map((c) =>
|
||||
m('button.emoji-cat-btn' + (c === cat ? '.active' : ''), {
|
||||
title: c,
|
||||
onclick: () => { ChatHubState.emojiCategory = c; },
|
||||
}, EMOJI_ICONS[c])
|
||||
)),
|
||||
m('.emoji-grid',
|
||||
emojis.map(e =>
|
||||
emojis.map((e) =>
|
||||
m('button.emoji-btn', {
|
||||
onclick: () => {
|
||||
insertEmojiIntoTextarea(e, onSelect);
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
const peopleUtil = require('people/people_util');
|
||||
const people = require('people/people');
|
||||
|
||||
// **************** utility functions ********************
|
||||
|
||||
@ -35,7 +33,7 @@ function loadDistantChatDetails(pid, apply) {
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsChats/getDistantChatStatus',
|
||||
{
|
||||
pid: pid,
|
||||
pid,
|
||||
},
|
||||
(detail, success) => {
|
||||
if (success && detail.retval) {
|
||||
@ -118,7 +116,7 @@ function renderChatMessage(rawText) {
|
||||
if (src) {
|
||||
parts.push(
|
||||
m('img.chat-embedded-image', {
|
||||
src: src,
|
||||
src,
|
||||
style: {
|
||||
maxWidth: '100%',
|
||||
maxHeight: '300px',
|
||||
@ -160,7 +158,7 @@ function renderChatMessage(rawText) {
|
||||
if (rawText.trim().startsWith('data:image/')) {
|
||||
const src = rawText.trim();
|
||||
return m('img.chat-embedded-image', {
|
||||
src: src,
|
||||
src,
|
||||
style: {
|
||||
maxWidth: '100%',
|
||||
maxHeight: '300px',
|
||||
@ -248,7 +246,7 @@ function renderTextWithEmoji(text) {
|
||||
const parts = [];
|
||||
let last = 0;
|
||||
let match;
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
|
||||
while ((match = emojiRegex.exec(text)) !== null) {
|
||||
if (match[0].length === 0) { emojiRegex.lastIndex++; continue; }
|
||||
if (match.index > last) parts.push(text.slice(last, match.index));
|
||||
@ -442,8 +440,8 @@ const Message = () => {
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
messageText: targetText,
|
||||
username: username,
|
||||
gxsId: gxsId,
|
||||
username,
|
||||
gxsId,
|
||||
};
|
||||
m.redraw();
|
||||
};
|
||||
@ -581,7 +579,7 @@ const ChatLobbyModel = {
|
||||
loadHistory(id, type) {
|
||||
const chatPeerId = {
|
||||
broadcast_status_peer_id: '00000000000000000000000000000000',
|
||||
type: type,
|
||||
type,
|
||||
peer_id: '00000000000000000000000000000000',
|
||||
distant_chat_id: '00000000000000000000000000000000',
|
||||
lobby_id: { xstr64: '0' },
|
||||
@ -594,7 +592,7 @@ const ChatLobbyModel = {
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsHistory/getMessages',
|
||||
{
|
||||
chatPeerId: chatPeerId,
|
||||
chatPeerId,
|
||||
loadCount: 20,
|
||||
},
|
||||
(data, success) => {
|
||||
@ -623,11 +621,11 @@ const ChatLobbyModel = {
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsHistory/getMessages',
|
||||
{
|
||||
chatPeerId: chatPeerId,
|
||||
chatPeerId,
|
||||
loadCount: 0,
|
||||
},
|
||||
(data, success) => {
|
||||
let msgs = (success && data && data.msgs) ? data.msgs : [];
|
||||
const msgs = (success && data && data.msgs) ? data.msgs : [];
|
||||
msgs.sort((a, b) => (a.sendTime || a.recvTime) - (b.sendTime || b.recvTime));
|
||||
ChatHubState.fullHistoryMessages = msgs;
|
||||
ChatHubState.isHistoryLoading = false;
|
||||
@ -642,7 +640,7 @@ const ChatLobbyModel = {
|
||||
'/rsChats/setIdentityForChatLobby',
|
||||
{
|
||||
lobby_id: { xstr64: lobbyId },
|
||||
nick: nick,
|
||||
nick,
|
||||
},
|
||||
() => m.route.set('/chat/:lobby', { lobby: lobbyId }),
|
||||
true
|
||||
@ -685,7 +683,7 @@ const ChatLobbyModel = {
|
||||
const id = this.lastLobbyId || m.route.param('lobby');
|
||||
const cid = {
|
||||
broadcast_status_peer_id: '00000000000000000000000000000000',
|
||||
type: type,
|
||||
type,
|
||||
peer_id: '00000000000000000000000000000000',
|
||||
distant_chat_id: '00000000000000000000000000000000',
|
||||
lobby_id: { xstr64: '0' },
|
||||
@ -805,13 +803,13 @@ const ChatLobbyModel = {
|
||||
'/rsChats/sendChat',
|
||||
{
|
||||
id: cid,
|
||||
msg: msg,
|
||||
msg,
|
||||
},
|
||||
(data, success) => {
|
||||
if (success) {
|
||||
const echoMsg = {
|
||||
chat_id: cid,
|
||||
msg: msg,
|
||||
msg,
|
||||
sendTime: Math.floor(Date.now() / 1000),
|
||||
lobby_peer_gxs_id: this.currentLobby.gxs_id,
|
||||
};
|
||||
|
||||
@ -10,8 +10,8 @@ const ConfigChat = () => {
|
||||
let maxStorageDays = 10;
|
||||
|
||||
// History states
|
||||
let historyEnable = { private: true, distant: true, lobby: true };
|
||||
let historySaveCount = { private: 500, distant: 500, lobby: 500 };
|
||||
const historyEnable = { private: true, distant: true, lobby: true };
|
||||
const historySaveCount = { private: 500, distant: 500, lobby: 500 };
|
||||
|
||||
function loadSettings() {
|
||||
// Load Own Identities
|
||||
|
||||
@ -579,8 +579,8 @@ const displayHiddenServiceInfo = () => {
|
||||
details && details.hiddenNodeAddress &&
|
||||
m('.hidden-service-info', { style: 'display: flex; flex-direction: column; gap: 0.75rem; width: 100%;' }, [
|
||||
m('p.proxy-description', { style: 'margin-bottom: 0.5rem; color: #475569;' }, details.hiddenType === 4
|
||||
? "I2P has been automatically configured by Retroshare. You shouldn't need to change anything here."
|
||||
: "Tor has been automatically configured by Retroshare. You shouldn't need to change anything here."
|
||||
? 'I2P has been automatically configured by Retroshare. You shouldn\'t need to change anything here.'
|
||||
: 'Tor has been automatically configured by Retroshare. You shouldn\'t need to change anything here.'
|
||||
),
|
||||
// Local Address + Local Port row
|
||||
m('.nw-config-row', { style: 'display: grid; grid-template-columns: 200px 1fr; gap: 1rem; align-items: center;' }, [
|
||||
|
||||
@ -2,7 +2,7 @@ const m = require('mithril');
|
||||
const rs = require('rswebui');
|
||||
const util = require('forums/forums_util');
|
||||
const peopleUtil = require('people/people_util');
|
||||
const { updatedisplayforums, loadPostContent, getTimestampValue, formatTimestamp } = require('./forums_util');
|
||||
const { loadPostContent, getTimestampValue, formatTimestamp } = require('./forums_util');
|
||||
|
||||
function createforum() {
|
||||
let title;
|
||||
@ -75,75 +75,6 @@ function createforum() {
|
||||
]),
|
||||
};
|
||||
}
|
||||
const EditThread = () => {
|
||||
let title = '';
|
||||
let body = '';
|
||||
return {
|
||||
oninit: (vnode) => {
|
||||
title = vnode.attrs.current_title;
|
||||
body = vnode.attrs.current_body;
|
||||
},
|
||||
view: (vnode) =>
|
||||
m('.widget', [
|
||||
m('h3', 'Edit Thread'),
|
||||
m('hr'),
|
||||
|
||||
m(
|
||||
'iddisplay',
|
||||
{
|
||||
style: { display: 'block ruby' }, // same line block ruby
|
||||
},
|
||||
[
|
||||
'Identity: ',
|
||||
m('h5[id=authid]', rs.userList.username(vnode.attrs.authorId)),
|
||||
]
|
||||
),
|
||||
m(
|
||||
'titledisplay',
|
||||
{
|
||||
style: { display: 'block ruby' },
|
||||
},
|
||||
[
|
||||
'Title: ',
|
||||
m('input[type=text][placeholder=Title]', {
|
||||
value: vnode.attrs.current_title,
|
||||
oninput: (e) => (title = e.target.value),
|
||||
}),
|
||||
]
|
||||
),
|
||||
m('textarea[rows=5]', {
|
||||
style: { width: '90%', display: 'block' },
|
||||
oninput: (e) => (body = e.target.value),
|
||||
value: vnode.attrs.current_body,
|
||||
}),
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
onclick: async () => {
|
||||
const res = await rs.rsJsonApiRequest('/rsgxsforums/createPost', {
|
||||
forumId: vnode.attrs.forumId,
|
||||
mBody: body,
|
||||
title,
|
||||
authorId: vnode.attrs.authorId,
|
||||
parentId: vnode.attrs.current_parent,
|
||||
origPostId: vnode.attrs.current_msgid,
|
||||
});
|
||||
res.body.retval === false
|
||||
? util.popupmessage([m('h3', 'Error'), m('hr'), m('p', res.body.errorMessage)])
|
||||
: util.popupmessage([
|
||||
m('h3', 'Success'),
|
||||
m('hr'),
|
||||
m('p', 'Thread edited successfully'),
|
||||
]);
|
||||
util.updatedisplayforums(vnode.attrs.forumId);
|
||||
m.redraw();
|
||||
},
|
||||
},
|
||||
'Add'
|
||||
),
|
||||
]),
|
||||
};
|
||||
};
|
||||
const AddThread = () => {
|
||||
let title = '';
|
||||
let body = '';
|
||||
@ -228,166 +159,6 @@ const AddThread = () => {
|
||||
|
||||
// getTimestampValue and formatTimestamp are imported from forums_util.js
|
||||
|
||||
function displaythread() {
|
||||
// recursive function to display all the threads
|
||||
let groupmessagepair;
|
||||
let unread;
|
||||
let editpermission = false;
|
||||
return {
|
||||
view: (v) => {
|
||||
const thread = v.attrs.threadStruct.thread;
|
||||
groupmessagepair = { first: thread.mMeta.mGroupId, second: thread.mMeta.mOrigMsgId };
|
||||
let parMap = [];
|
||||
if (util.Data.ParentThreadMap[thread.mMeta.mOrigMsgId]) {
|
||||
parMap = util.Data.ParentThreadMap[thread.mMeta.mOrigMsgId];
|
||||
}
|
||||
unread = thread.mMeta.mMsgStatus === util.THREAD_UNREAD;
|
||||
v.attrs.identity &&
|
||||
v.attrs.identity.map((val) => {
|
||||
if (val.localeCompare(thread.mMeta.mAuthorId) === 0) {
|
||||
// if the author of the thread matches one of our own ids
|
||||
editpermission = true;
|
||||
}
|
||||
});
|
||||
return [
|
||||
m(
|
||||
'tr',
|
||||
{
|
||||
style: unread ? { fontWeight: 'bold' } : '',
|
||||
},
|
||||
[
|
||||
Object.keys(parMap).length // if this thread has some replies
|
||||
? m(
|
||||
'td',
|
||||
m('i.fas.fa-angle-right', {
|
||||
class: 'fa-rotate-' + (v.attrs.threadStruct.showReplies ? '90' : '0'),
|
||||
style: 'margin-top:12px',
|
||||
onclick: () => {
|
||||
v.attrs.threadStruct.showReplies = !v.attrs.threadStruct.showReplies;
|
||||
},
|
||||
})
|
||||
)
|
||||
: m('td', ''),
|
||||
|
||||
m(
|
||||
'td',
|
||||
{
|
||||
style: {
|
||||
position: 'relative',
|
||||
'--replyDepth': v.attrs.replyDepth,
|
||||
left: 'calc(30px*var(--replyDepth))', // shifts reply by 30 px
|
||||
padding: '10px 0',
|
||||
},
|
||||
},
|
||||
[
|
||||
m('div.date', { style: { fontSize: '0.8em', color: '#888' } },
|
||||
formatTimestamp(thread.mMeta.mPublishTs)
|
||||
),
|
||||
m('div.title', {
|
||||
style: { fontWeight: 'bold', fontSize: '1.1em', cursor: 'pointer', margin: '5px 0' },
|
||||
onclick: async () => {
|
||||
v.attrs.changeThread(thread.mMeta.mOrigMsgId);
|
||||
if (unread) {
|
||||
const res = await rs.rsJsonApiRequest('/rsgxsforums/markRead', {
|
||||
messageId: groupmessagepair,
|
||||
read: true,
|
||||
});
|
||||
if (res.body.retval) {
|
||||
updatedisplayforums(thread.mMeta.mGroupId);
|
||||
m.redraw();
|
||||
}
|
||||
}
|
||||
},
|
||||
ondblclick: () =>
|
||||
(v.attrs.threadStruct.showReplies = !v.attrs.threadStruct.showReplies),
|
||||
}, [
|
||||
thread.mMeta.mMsgName,
|
||||
m('options', { style: 'display:block; margin-top: 5px;' }, [
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
style: 'font-size:12px; margin-right: 5px;',
|
||||
onclick: (e) => {
|
||||
e.stopPropagation();
|
||||
util.popupmessage(
|
||||
m(AddThread, {
|
||||
parent_thread: thread.mMeta.mMsgName,
|
||||
forumId: thread.mMeta.mGroupId,
|
||||
authorId: v.attrs.identity,
|
||||
parentId: thread.mMeta.mMsgId,
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
'Reply'
|
||||
),
|
||||
editpermission &&
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
style: 'font-size:12px; margin-right: 5px;',
|
||||
onclick: async (e) => {
|
||||
e.stopPropagation();
|
||||
const body = await loadPostContent(
|
||||
thread.mMeta.mGroupId,
|
||||
thread.mMeta.mOrigMsgId
|
||||
);
|
||||
util.popupmessage(
|
||||
m(EditThread, {
|
||||
current_thread: thread.mMeta.mMsgName,
|
||||
forumId: thread.mMeta.mGroupId,
|
||||
current_title: thread.mMeta.mMsgName,
|
||||
current_body: body || '',
|
||||
authorId: thread.mMeta.mAuthorId,
|
||||
current_parent: thread.mMeta.mParentId,
|
||||
current_msgid: thread.mMeta.mOrigMsgId,
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
'Edit'
|
||||
),
|
||||
m(
|
||||
'button',
|
||||
{
|
||||
style: { fontSize: '12px' },
|
||||
onclick: async (e) => {
|
||||
e.stopPropagation();
|
||||
const res = await rs.rsJsonApiRequest('/rsgxsforums/markRead', {
|
||||
messageId: groupmessagepair,
|
||||
read: !unread ? true : false,
|
||||
});
|
||||
|
||||
if (res.body.retval) {
|
||||
updatedisplayforums(thread.mMeta.mGroupId);
|
||||
m.redraw();
|
||||
}
|
||||
},
|
||||
},
|
||||
unread ? 'Mark Read' : 'Mark Unread'
|
||||
),
|
||||
]),
|
||||
]),
|
||||
m('div.author', { style: { fontSize: '0.9em', fontStyle: 'italic' } }, rs.userList.username(thread.mMeta.mAuthorId)),
|
||||
]
|
||||
),
|
||||
]
|
||||
),
|
||||
v.attrs.threadStruct.showReplies &&
|
||||
Object.keys(parMap).map((key, index) =>
|
||||
m(displaythread, {
|
||||
// recursive call to all replies
|
||||
threadStruct: util.Data.Threads[parMap[key].mGroupId][parMap[key].mOrigMsgId],
|
||||
replyDepth: v.attrs.replyDepth + 1,
|
||||
identity: v.attrs.identity,
|
||||
changeThread: v.attrs.changeThread,
|
||||
})
|
||||
),
|
||||
];
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const ThreadView = () => {
|
||||
let ownId;
|
||||
return {
|
||||
@ -449,7 +220,7 @@ const ThreadView = () => {
|
||||
style: { marginRight: '10px' },
|
||||
onclick: () => util.popupmessage(m(AddThread, {
|
||||
parent_thread: meta.mMsgName,
|
||||
forumId: forumId,
|
||||
forumId,
|
||||
authorId: ownId,
|
||||
parentId: msgId,
|
||||
}))
|
||||
|
||||
@ -106,7 +106,7 @@ async function updatedisplayforums(keyid) {
|
||||
|
||||
const threadStruct = {
|
||||
thread: { mMeta: meta, mMsg: null },
|
||||
replies: replies,
|
||||
replies,
|
||||
showReplies: false,
|
||||
};
|
||||
|
||||
@ -156,7 +156,7 @@ async function loadPostContent(forumId, msgId) {
|
||||
|
||||
try {
|
||||
const res = await rs.rsJsonApiRequest('/rsgxsforums/getForumContent', {
|
||||
forumId: forumId,
|
||||
forumId,
|
||||
msgsIds: [msgId],
|
||||
});
|
||||
if (res && res.body && res.body.retval && res.body.msgs && res.body.msgs.length > 0) {
|
||||
|
||||
@ -41,7 +41,7 @@ function renderPolygon(shapePoints, x, y, angle, shapeAngle, size, color) {
|
||||
|
||||
function toSvg(hash, width) {
|
||||
if (!hash || hash.length < 18) {
|
||||
hash = "00000000000000000000000000000000";
|
||||
hash = '00000000000000000000000000000000';
|
||||
}
|
||||
|
||||
const csh = parseInt(hash.substr(0, 1), 16);
|
||||
@ -99,4 +99,4 @@ function toSvg(hash, width) {
|
||||
|
||||
module.exports = {
|
||||
toSvg
|
||||
};
|
||||
};
|
||||
|
||||
@ -18,7 +18,7 @@ function formatFileSize(bytes) {
|
||||
const Layout = () => {
|
||||
let showCc = false;
|
||||
let showBcc = false;
|
||||
let ownAvatars = {};
|
||||
const ownAvatars = {};
|
||||
let attachments = [];
|
||||
let showEmojiPicker = false;
|
||||
let emojiSearch = '';
|
||||
@ -397,7 +397,7 @@ const Layout = () => {
|
||||
const attHtml = `
|
||||
<br/><hr style="border:none;border-top:1px solid #e2e8f0;margin:1rem 0;"/><div style="margin-top:10px;font-weight:bold;color:#475569;font-size:0.9rem;">Attachments (${attachments.length}):</div>
|
||||
<ul style="list-style:none;padding:0;margin:6px 0;">
|
||||
${attachments.map(att => `<li style="padding:4px 0;color:#1e293b;font-size:0.875rem;">📎 <b>${att.name}</b> <span style="color:#94a3b8;font-size:0.8em;">(${att.size})</span></li>`).join('')}
|
||||
${attachments.map((att) => `<li style="padding:4px 0;color:#1e293b;font-size:0.875rem;">📎 <b>${att.name}</b> <span style="color:#94a3b8;font-size:0.8em;">(${att.size})</span></li>`).join('')}
|
||||
</ul>
|
||||
`;
|
||||
fullMailBody += attHtml;
|
||||
@ -701,7 +701,7 @@ const Layout = () => {
|
||||
}),
|
||||
]),
|
||||
!emojiSearch && m('.emoji-cat-bar', { style: 'display: flex; background: #f8fafc; border-bottom: 1px solid #e2e8f0; padding: 0.25rem; overflow-x: auto;' },
|
||||
chatEmoji.EMOJI_CATEGORIES.map(c =>
|
||||
chatEmoji.EMOJI_CATEGORIES.map((c) =>
|
||||
m('button', {
|
||||
style: `border: none; background: ${c === emojiCategory ? '#ffffff' : 'transparent'}; border-radius: 0.25rem; padding: 0.3rem 0.4rem; cursor: pointer; font-size: 1rem; box-shadow: ${c === emojiCategory ? '0 1px 2px rgba(0,0,0,0.1)' : 'none'};`,
|
||||
title: c,
|
||||
@ -711,9 +711,9 @@ const Layout = () => {
|
||||
),
|
||||
m('.emoji-grid-body', { style: 'padding: 0.5rem; display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.25rem; max-height: 230px; overflow-y: auto;' },
|
||||
(emojiSearch
|
||||
? Object.values(chatEmoji.EMOJI_DATA).flat().filter(e => e.includes(emojiSearch))
|
||||
? Object.values(chatEmoji.EMOJI_DATA).flat().filter((e) => e.includes(emojiSearch))
|
||||
: (chatEmoji.EMOJI_DATA[emojiCategory] || [])
|
||||
).map(e =>
|
||||
).map((e) =>
|
||||
m('button', {
|
||||
style: 'border: none; background: transparent; font-size: 1.25rem; cursor: pointer; padding: 0.25rem; border-radius: 0.25rem; transition: background 0.15s ease;',
|
||||
onmouseenter: (ev) => (ev.currentTarget.style.background = '#f1f5f9'),
|
||||
|
||||
@ -195,7 +195,7 @@ const GenericMailList = () => {
|
||||
m(util.MessageSummary, {
|
||||
key: msg.msgId,
|
||||
details: msg,
|
||||
category: category,
|
||||
category,
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
@ -622,11 +622,11 @@ const Table = () => {
|
||||
};
|
||||
|
||||
let totalItems = 0;
|
||||
let tbody = v.children[0];
|
||||
const tbody = v.children[0];
|
||||
if (tbody && tbody.children) {
|
||||
const flatChildren = Array.isArray(tbody.children) ? tbody.children.flat().filter(Boolean) : [tbody.children].filter(Boolean);
|
||||
totalItems = flatChildren.length;
|
||||
|
||||
|
||||
const start = currentPage * pageSize;
|
||||
const end = start + pageSize;
|
||||
tbody.children = flatChildren.slice(start, end);
|
||||
|
||||
@ -149,7 +149,7 @@ function sendDirectChatMessage() {
|
||||
'/rsChats/sendChat',
|
||||
{
|
||||
id: { type: 1, peer_id: State.currentChatPeerId },
|
||||
msg: msg,
|
||||
msg,
|
||||
},
|
||||
(data, success) => {
|
||||
if (success) {
|
||||
|
||||
@ -100,14 +100,6 @@ const ChatTab = () => {
|
||||
|
||||
const canTalk = State.distantChatStatus && State.distantChatStatus.status === 2;
|
||||
|
||||
// Filter history by search query for history modal
|
||||
const query = (State.historySearchQuery || '').toLowerCase();
|
||||
const filteredHistory = (State.fullHistoryMessages || []).filter((msg) => {
|
||||
if (!query) return true;
|
||||
const text = (msg.msg || msg.message || '').toLowerCase();
|
||||
return text.includes(query);
|
||||
});
|
||||
|
||||
return m('.network-chat-view', [
|
||||
m('.chat-identity-select-container', {
|
||||
style: 'padding: 0.5rem 1rem; background-color: #ffffff; border-bottom: 1px solid #cbd5e1; display: flex; align-items: center; justify-content: space-between; font-size: 0.85rem;',
|
||||
|
||||
@ -33,7 +33,7 @@ const PeopleSidebar = () => {
|
||||
},
|
||||
view: () => {
|
||||
// 1. Determine list based on mainTab ('people' vs 'chats')
|
||||
let displayItems = [];
|
||||
let displayItems;
|
||||
|
||||
// 0. Compute active chats count (conversations with real message history)
|
||||
const allUserGroupIds = new Set((rs.userList.users || []).map((u) => u.mGroupId));
|
||||
@ -47,7 +47,7 @@ const PeopleSidebar = () => {
|
||||
});
|
||||
|
||||
if (State.mainTab === 'people') {
|
||||
let baseList = [];
|
||||
let baseList;
|
||||
if (State.activeFilter === 'own') {
|
||||
baseList = peopleUtil.sortIds(State.ownGxsIds) || [];
|
||||
} else if (State.activeFilter === 'contacts') {
|
||||
@ -57,13 +57,13 @@ const PeopleSidebar = () => {
|
||||
}
|
||||
|
||||
displayItems = baseList.filter((item) => {
|
||||
let name = State.activeFilter === 'own' ? (rs.userList.username(item) || 'Unknown') : (item.mGroupName || 'Unknown');
|
||||
const name = State.activeFilter === 'own' ? (rs.userList.username(item) || 'Unknown') : (item.mGroupName || 'Unknown');
|
||||
return name.toLowerCase().includes(State.searchString.toLowerCase());
|
||||
});
|
||||
|
||||
displayItems.sort((a, b) => {
|
||||
let nameA = State.activeFilter === 'own' ? (rs.userList.username(a) || '') : (a.mGroupName || '');
|
||||
let nameB = State.activeFilter === 'own' ? (rs.userList.username(b) || '') : (b.mGroupName || '');
|
||||
const nameA = State.activeFilter === 'own' ? (rs.userList.username(a) || '') : (a.mGroupName || '');
|
||||
const nameB = State.activeFilter === 'own' ? (rs.userList.username(b) || '') : (b.mGroupName || '');
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -359,7 +359,7 @@ function loadChatMessages() {
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsHistory/getMessages',
|
||||
{
|
||||
chatPeerId: chatPeerId,
|
||||
chatPeerId,
|
||||
loadCount: 50,
|
||||
},
|
||||
(data, success) => {
|
||||
@ -509,7 +509,7 @@ function preloadAllChatHistory() {
|
||||
if (!existing || lastTime > existing.lastTime) {
|
||||
State.chatHistoryMap[gxsId] = {
|
||||
lastMsg: last.message || last.msg || '',
|
||||
lastTime: lastTime,
|
||||
lastTime,
|
||||
};
|
||||
m.redraw();
|
||||
}
|
||||
@ -573,7 +573,7 @@ function loadAllHistoryForSelectedPeer(callback) {
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsHistory/getMessages',
|
||||
{
|
||||
chatPeerId: chatPeerId,
|
||||
chatPeerId,
|
||||
loadCount: 0, // 0 = load all messages in C++
|
||||
},
|
||||
(msgData, success) => {
|
||||
@ -588,7 +588,7 @@ function loadAllHistoryForSelectedPeer(callback) {
|
||||
const key = `${mItem.sendTime || mItem.recvTime}_${text}`;
|
||||
if (!map.has(key)) map.set(key, mItem);
|
||||
});
|
||||
let uniqueMsgs = Array.from(map.values());
|
||||
const uniqueMsgs = Array.from(map.values());
|
||||
uniqueMsgs.sort((a, b) => (a.sendTime || a.recvTime) - (b.sendTime || b.recvTime));
|
||||
State.fullHistoryMessages = uniqueMsgs;
|
||||
State.isHistoryLoading = false;
|
||||
|
||||
@ -70,7 +70,7 @@ const UserAvatar = () => ({
|
||||
width: sizeStr,
|
||||
height: sizeStr,
|
||||
borderRadius: isSquare ? '0' : '50%',
|
||||
backgroundColor: backgroundColor,
|
||||
backgroundColor,
|
||||
}
|
||||
},
|
||||
m('p', {
|
||||
|
||||
51
webui-src/eslint.config.mjs
Normal file
51
webui-src/eslint.config.mjs
Normal file
@ -0,0 +1,51 @@
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: ['app/mithril.js', 'assets/**', 'make-src/**'],
|
||||
},
|
||||
{
|
||||
files: ['app/**/*.js'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'commonjs',
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.commonjs,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
'linebreak-style': ['off', 'unix'],
|
||||
quotes: ['error', 'single'],
|
||||
semi: ['error', 'always'],
|
||||
'arrow-spacing': ['error', { before: true, after: true }],
|
||||
'arrow-parens': ['error', 'always'],
|
||||
'comma-style': ['error', 'last'],
|
||||
'comma-spacing': ['error', { before: false, after: true }],
|
||||
camelcase: ['error', {
|
||||
allow: ['^UNSAFE_'],
|
||||
properties: 'never',
|
||||
ignoreGlobals: true,
|
||||
}],
|
||||
'eol-last': 'error',
|
||||
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-trailing-spaces': 'error',
|
||||
'no-unexpected-multiline': 'error',
|
||||
'no-unreachable': 'error',
|
||||
'no-var': 'warn',
|
||||
'no-unused-vars': ['error', {
|
||||
args: 'none',
|
||||
caughtErrors: 'none',
|
||||
ignoreRestSiblings: true,
|
||||
vars: 'all',
|
||||
}],
|
||||
'object-shorthand': 'error',
|
||||
'prefer-const': ['error', { destructuring: 'all' }],
|
||||
'semi-style': ['warn', 'last'],
|
||||
'spaced-comment': ['warn', 'always'],
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -8,7 +8,7 @@ echo "### Starting WebUI build ###"
|
||||
set src=%~dp0..\..\webui-src
|
||||
|
||||
rem Output destination
|
||||
if "%~1" == "" (
|
||||
if "%~1"=="" (
|
||||
set publicdest=%~dp0..\..\webui
|
||||
) else (
|
||||
set publicdest=%~1\webui
|
||||
@ -36,6 +36,7 @@ copy %src%\make-src\template.js %publicdest%\app.js
|
||||
|
||||
pushd %src%\app
|
||||
set "basefolder=%cd%\"
|
||||
set "lastsection="
|
||||
for /R %%F in (*.js) do call :addfile-js "%basefolder%" "%%F"
|
||||
popd
|
||||
|
||||
@ -54,7 +55,15 @@ set registername=%~dpn2
|
||||
set registername=!registername:%basefolder%=!
|
||||
set registername=%registername:\=/%
|
||||
|
||||
echo - adding %registername% ...
|
||||
for /f "tokens=1,2 delims=/" %%A in ("!registername!") do (
|
||||
if "%%B"=="" (
|
||||
echo - adding !registername! ...
|
||||
set "lastsection="
|
||||
) else if not "!lastsection!"=="%%A" (
|
||||
echo - adding %%A/* ...
|
||||
set "lastsection=%%A"
|
||||
)
|
||||
)
|
||||
echo require.register("%registername%", function(exports, require, module) { >> %publicdest%\app.js
|
||||
type %fname% >> %publicdest%\app.js
|
||||
echo. >> %publicdest%\app.js
|
||||
|
||||
@ -1,68 +1,85 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# create webfiles from sources at compile time (works without npm/node.js)
|
||||
# Create webfiles from sources at compile time (works without npm/node.js)
|
||||
#
|
||||
# Usage: build.sh [DEST_PARENT] [TARGET_FILE] [EXTRA_COPY_DIR]
|
||||
# DEST_PARENT parent dir of the generated webui/ (default: repo root)
|
||||
# TARGET_FILE build only this file (index.html|styles.css|app.js); default: all
|
||||
# EXTRA_COPY_DIR also copy TARGET_FILE into EXTRA_COPY_DIR/webui/
|
||||
|
||||
set -eu
|
||||
|
||||
echo "### Starting WebUI build ###"
|
||||
|
||||
src=$(readlink -f $(dirname $0))/../../webui-src
|
||||
# Resolve the script's own directory portably.
|
||||
script_dir=$(cd -- "$(dirname -- "$0")" && pwd -P)
|
||||
src="$script_dir/../../webui-src"
|
||||
|
||||
if [ "$1" = "" ]; then
|
||||
publicdest=$(readlink -f $(dirname $0))/../../webui
|
||||
dest_parent="${1:-}"
|
||||
target="${2:-}"
|
||||
extra_copy_dir="${3:-}"
|
||||
|
||||
if [ -z "$dest_parent" ]; then
|
||||
publicdest="$script_dir/../../webui"
|
||||
else
|
||||
publicdest=$1/webui
|
||||
publicdest="$dest_parent/webui"
|
||||
fi
|
||||
|
||||
if [ "$2" = "" ]; then
|
||||
if [ -d "$publicdest" ]; then
|
||||
echo removing existing $publicdest
|
||||
rm $publicdest -R
|
||||
fi
|
||||
# Full rebuild (no specific target): remove any existing output first.
|
||||
if [ -z "$target" ] && [ -d "$publicdest" ]; then
|
||||
echo "removing existing $publicdest"
|
||||
rm -rf -- "$publicdest"
|
||||
fi
|
||||
|
||||
if [ ! -d "$publicdest" ]; then
|
||||
echo creating $publicdest
|
||||
mkdir $publicdest
|
||||
mkdir -p -- "$publicdest"
|
||||
|
||||
if [ -z "$target" ] || [ "$target" = "index.html" ]; then
|
||||
echo "copying html file"
|
||||
cp -- "$src/index.html" "$publicdest/"
|
||||
fi
|
||||
|
||||
# For using recursive directory search(requires bash v4+)
|
||||
shopt -s globstar
|
||||
|
||||
if [ "$2" = "" ]||[ "$2" = "index.html" ]; then
|
||||
echo copying html file
|
||||
cp $src/index.html $publicdest/
|
||||
if [ -z "$target" ] || [ "$target" = "styles.css" ]; then
|
||||
echo "copying css file"
|
||||
cp -- "$src/styles.css" "$publicdest/"
|
||||
fi
|
||||
|
||||
if [ "$2" = "" ]||[ "$2" = "styles.css" ]; then
|
||||
echo copying css file
|
||||
cp $src/styles.css $publicdest/
|
||||
if [ -z "$target" ] || [ "$target" = "app.js" ]; then
|
||||
echo "building app.js:"
|
||||
echo "- copying template.js ..."
|
||||
cp -- "$src/make-src/template.js" "$publicdest/app.js"
|
||||
|
||||
js_root="$src/app"
|
||||
find "$js_root" -type f -name '*.js' | LC_ALL=C sort | while IFS= read -r filename; do
|
||||
fname="${filename#"$js_root/"}"
|
||||
fname="${fname%.*}"
|
||||
case "$fname" in
|
||||
*/*)
|
||||
section="${fname%%/*}/*"
|
||||
if [ "$section" != "${last_section:-}" ]; then
|
||||
echo "- adding $section ..."
|
||||
last_section="$section"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "- adding $fname ..."
|
||||
last_section=
|
||||
;;
|
||||
esac
|
||||
{
|
||||
printf 'require.register("%s", function(exports, require, module) {\n' "$fname"
|
||||
cat -- "$filename"
|
||||
printf '\n});\n'
|
||||
} >>"$publicdest/app.js"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "$2" = "" ]||[ "$2" = "app.js" ]; then
|
||||
echo building app.js:
|
||||
echo - copying template.js ...
|
||||
cp $src/make-src/template.js $publicdest/app.js
|
||||
echo "copying assets folder"
|
||||
cp -R -- "$src/assets/." "$publicdest/"
|
||||
|
||||
js_source=$src/app/
|
||||
for filename in $src/app/**/*.js; do
|
||||
fname="${filename#$js_source}"
|
||||
fname="${fname%.*}"
|
||||
echo - adding $fname ...
|
||||
echo require.register\(\"$fname\", function\(exports, require, module\) { >> $publicdest/app.js
|
||||
cat $filename >> $publicdest/app.js
|
||||
echo >> $publicdest/app.js
|
||||
echo }\)\; >> $publicdest/app.js
|
||||
done
|
||||
if [ -n "$target" ] && [ -n "$extra_copy_dir" ]; then
|
||||
mkdir -p -- "$extra_copy_dir/webui"
|
||||
echo "copying $target to $extra_copy_dir/webui/$target"
|
||||
cp -- "$publicdest/$target" "$extra_copy_dir/webui/$target"
|
||||
fi
|
||||
|
||||
echo copying assets folder
|
||||
cp -r $src/assets/* $publicdest/
|
||||
|
||||
if [ "$2" != "" ]&&[ "$3" != "" ]; then
|
||||
if [ ! -d "$3/webui" ]; then
|
||||
echo creating $3/webui
|
||||
mkdir $3/webui
|
||||
fi
|
||||
echo copying $2 nach $3/webui/$2
|
||||
cp $publicdest/$2 $3/webui/$2
|
||||
fi
|
||||
echo "### WebUI build complete ###"
|
||||
|
||||
1311
webui-src/package-lock.json
generated
Normal file
1311
webui-src/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,17 @@
|
||||
"description": "Retroshare's Web Interface",
|
||||
"scripts": {
|
||||
"watch": "rm ./styles.css && sass --watch --embed-sources --embed-source-map ./app/scss/main.scss ./styles.css",
|
||||
"build": "sass --no-source-map --style=compressed ./app/scss/main.scss ./styles.css"
|
||||
"build": "sass --no-source-map --style=compressed ./app/scss/main.scss ./styles.css && sh ./make-src/build.sh",
|
||||
"lint": "eslint app && node --check ../webui/app.js && sh -n make-src/build.sh && echo 'Lint checks passed.'"
|
||||
},
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"devDependencies": {
|
||||
"sass": "^1.60.0"
|
||||
"@eslint/js": "^10.0.1",
|
||||
"eslint": "^10.8.0",
|
||||
"globals": "^17.8.0",
|
||||
"sass": "1.97.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,240 +0,0 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
devDependencies:
|
||||
sass:
|
||||
specifier: ^1.60.0
|
||||
version: 1.97.3
|
||||
|
||||
packages:
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.6':
|
||||
resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@parcel/watcher-darwin-arm64@2.5.6':
|
||||
resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@parcel/watcher-darwin-x64@2.5.6':
|
||||
resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@parcel/watcher-freebsd-x64@2.5.6':
|
||||
resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@parcel/watcher-linux-arm-glibc@2.5.6':
|
||||
resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.6':
|
||||
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.6':
|
||||
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.6':
|
||||
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.6':
|
||||
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-x64-musl@2.5.6':
|
||||
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-win32-arm64@2.5.6':
|
||||
resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@parcel/watcher-win32-ia32@2.5.6':
|
||||
resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@parcel/watcher-win32-x64@2.5.6':
|
||||
resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@parcel/watcher@2.5.6':
|
||||
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
chokidar@4.0.3:
|
||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||
engines: {node: '>= 14.16.0'}
|
||||
|
||||
detect-libc@2.1.2:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
immutable@5.1.5:
|
||||
resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==}
|
||||
|
||||
is-extglob@2.1.1:
|
||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
node-addon-api@7.1.1:
|
||||
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
|
||||
|
||||
picomatch@4.0.3:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
readdirp@4.1.2:
|
||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||
engines: {node: '>= 14.18.0'}
|
||||
|
||||
sass@1.97.3:
|
||||
resolution: {integrity: sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-darwin-arm64@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-darwin-x64@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-freebsd-x64@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm-glibc@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-linux-x64-musl@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-win32-arm64@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-win32-ia32@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-win32-x64@2.5.6':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher@2.5.6':
|
||||
dependencies:
|
||||
detect-libc: 2.1.2
|
||||
is-glob: 4.0.3
|
||||
node-addon-api: 7.1.1
|
||||
picomatch: 4.0.3
|
||||
optionalDependencies:
|
||||
'@parcel/watcher-android-arm64': 2.5.6
|
||||
'@parcel/watcher-darwin-arm64': 2.5.6
|
||||
'@parcel/watcher-darwin-x64': 2.5.6
|
||||
'@parcel/watcher-freebsd-x64': 2.5.6
|
||||
'@parcel/watcher-linux-arm-glibc': 2.5.6
|
||||
'@parcel/watcher-linux-arm-musl': 2.5.6
|
||||
'@parcel/watcher-linux-arm64-glibc': 2.5.6
|
||||
'@parcel/watcher-linux-arm64-musl': 2.5.6
|
||||
'@parcel/watcher-linux-x64-glibc': 2.5.6
|
||||
'@parcel/watcher-linux-x64-musl': 2.5.6
|
||||
'@parcel/watcher-win32-arm64': 2.5.6
|
||||
'@parcel/watcher-win32-ia32': 2.5.6
|
||||
'@parcel/watcher-win32-x64': 2.5.6
|
||||
optional: true
|
||||
|
||||
chokidar@4.0.3:
|
||||
dependencies:
|
||||
readdirp: 4.1.2
|
||||
|
||||
detect-libc@2.1.2:
|
||||
optional: true
|
||||
|
||||
immutable@5.1.5: {}
|
||||
|
||||
is-extglob@2.1.1:
|
||||
optional: true
|
||||
|
||||
is-glob@4.0.3:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
optional: true
|
||||
|
||||
node-addon-api@7.1.1:
|
||||
optional: true
|
||||
|
||||
picomatch@4.0.3:
|
||||
optional: true
|
||||
|
||||
readdirp@4.1.2: {}
|
||||
|
||||
sass@1.97.3:
|
||||
dependencies:
|
||||
chokidar: 4.0.3
|
||||
immutable: 5.1.5
|
||||
source-map-js: 1.2.1
|
||||
optionalDependencies:
|
||||
'@parcel/watcher': 2.5.6
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
@ -72,7 +72,7 @@ win32-g++ {
|
||||
} else {
|
||||
# create dummy files, we need it to include files on first try
|
||||
|
||||
system(bash webui-src/make-src/build.sh .)
|
||||
system(sh webui-src/make-src/build.sh .)
|
||||
|
||||
WEBUI_SRC_SCRIPT = webui-src/make-src/build.sh
|
||||
|
||||
@ -80,19 +80,19 @@ win32-g++ {
|
||||
|
||||
create_webfiles_html.output = webui/index.html
|
||||
create_webfiles_html.input = WEBUI_SRC_HTML
|
||||
create_webfiles_html.commands = bash $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ index.html .
|
||||
create_webfiles_html.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ index.html .
|
||||
create_webfiles_html.variable_out = JUNK
|
||||
create_webfiles_html.CONFIG = combine no_link
|
||||
|
||||
create_webfiles_js.output = webui/app.js
|
||||
create_webfiles_js.input = WEBUI_SRC_JS
|
||||
create_webfiles_js.commands = bash $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ app.js .
|
||||
create_webfiles_js.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ app.js .
|
||||
create_webfiles_js.variable_out = JUNK
|
||||
create_webfiles_js.CONFIG = combine no_link
|
||||
|
||||
create_webfiles_css.output = webui/styles.css
|
||||
create_webfiles_css.input = WEBUI_SRC_CSS
|
||||
create_webfiles_css.commands = bash $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ styles.css .
|
||||
create_webfiles_css.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ styles.css .
|
||||
create_webfiles_css.variable_out = JUNK
|
||||
create_webfiles_css.CONFIG = combine no_link
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user