mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-12 19:50:04 +05:00
859 lines
28 KiB
JavaScript
859 lines
28 KiB
JavaScript
const m = require('mithril');
|
|
const rs = require('rswebui');
|
|
const util = require('channels/channels_util');
|
|
const widget = require('widgets');
|
|
const Data = util.Data;
|
|
const peopleUtil = require('people/people_util');
|
|
const sha1 = require('channels/sha1');
|
|
const fileUtil = require('files/files_util');
|
|
const fileDown = require('files/files_downloads');
|
|
|
|
const filesUploadHashes = {
|
|
// figure out a better way later.
|
|
PostFiles: [],
|
|
Thumbnail: [],
|
|
};
|
|
|
|
async function parsefile(file, type) {
|
|
const fileSize = file.size;
|
|
const chunkSize = 1024 * 1024; // bytes
|
|
let offset = 0;
|
|
let chunkreaderblock = null;
|
|
const hash = sha1.create();
|
|
const ansList = [];
|
|
|
|
// const readEventHandler = async function (evt) {
|
|
// if (evt.target.error == null) {
|
|
// offset += evt.target.result.length;
|
|
// await hash.update(evt.target.result);
|
|
// } else {
|
|
// console.log('Read error: ' + evt.target.error);
|
|
// return;
|
|
// }
|
|
// if (offset >= fileSize) {
|
|
// const ans = await hash.hex();
|
|
// console.log(ans);
|
|
// ansList.push(ans);
|
|
// if (type.localeCompare('multiple') === 0) {
|
|
// filesUploadHashes.PostFiles.push(ans);
|
|
// } else {
|
|
// filesUploadHashes.Thumbnail.push(ans);
|
|
// }
|
|
// return;
|
|
// }
|
|
|
|
// // of to the next chunk
|
|
// await chunkreaderblock(offset, chunkSize, file);
|
|
// return ansList;
|
|
// };
|
|
|
|
chunkreaderblock = async function (_offset, length, _file) {
|
|
// const reader = new FileReader();
|
|
const blob = await _file.slice(_offset, length + _offset);
|
|
const data = await blob.text();
|
|
offset += data.length;
|
|
await hash.update(data);
|
|
if (offset >= fileSize) {
|
|
const ans = await hash.hex();
|
|
// console.log(ans);
|
|
// ansList.push(ans);
|
|
if (type.localeCompare('multiple') === 0) {
|
|
filesUploadHashes.PostFiles.push(ans);
|
|
} else {
|
|
filesUploadHashes.Thumbnail.push(ans);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// of to the next chunk
|
|
await chunkreaderblock(offset, chunkSize, file);
|
|
};
|
|
|
|
// read with the first block
|
|
await chunkreaderblock(offset, chunkSize, file);
|
|
return ansList;
|
|
}
|
|
const messageGroups = ['Public', 'Restricted Circle', 'Restricted Node Group'];
|
|
const messageGroupsCode = [util.PUBLIC, util.EXTERNAL, util.NODES_GROUP]; // rsgxscirles.h:50
|
|
|
|
function createchannel() {
|
|
let title;
|
|
let body;
|
|
let identity;
|
|
let thumbnail;
|
|
let selectedGroup = messageGroups[0];
|
|
let selectedGroupCode = messageGroupsCode[0];
|
|
let selectedCircle;
|
|
let circles;
|
|
return {
|
|
oninit: async (vnode) => {
|
|
if (vnode.attrs.authorId) {
|
|
identity = vnode.attrs.authorId[0];
|
|
}
|
|
|
|
const res = await rs.rsJsonApiRequest('/rsgxscircles/getCirclesSummaries');
|
|
if (res.body.retval) {
|
|
circles = res.body.circles;
|
|
selectedCircle = circles[0].mGroupName;
|
|
}
|
|
},
|
|
view: (vnode) =>
|
|
m('.widget', [
|
|
m('h3', 'Create Channel'),
|
|
m('hr'),
|
|
m('input[type=text][placeholder=Title]', {
|
|
style: { float: 'left' },
|
|
oninput: (e) => (title = e.target.value),
|
|
}),
|
|
m('div', { style: { float: 'right', marginTop: '10px', marginBottom: '10px' } }, [
|
|
m('label[for=thumbnail]', 'Thumbnail: '),
|
|
m('input[type=file][name=files][id=thumbnail][accept=image/*]', {
|
|
onchange: async (e) => {
|
|
const reader = new FileReader();
|
|
reader.onloadend = function () {
|
|
thumbnail = reader.result.substring(reader.result.indexOf(',') + 1);
|
|
};
|
|
reader.readAsDataURL(e.target.files[0]);
|
|
},
|
|
}),
|
|
]),
|
|
|
|
m('div', { style: { float: 'right', marginTop: '10px', marginBottom: '10px' } }, [
|
|
m('label[for=idtags]', 'Select identity: '),
|
|
m(
|
|
'select[id=idtags]',
|
|
{
|
|
value: identity,
|
|
onchange: (e) => {
|
|
identity = vnode.attrs.authorId[e.target.selectedIndex];
|
|
},
|
|
},
|
|
[
|
|
vnode.attrs.authorId &&
|
|
vnode.attrs.authorId.map((o) =>
|
|
m(
|
|
'option',
|
|
{ value: o },
|
|
rs.userList.userMap[o]
|
|
? rs.userList.userMap[o].toLocaleString() + ' (' + o.slice(0, 8) + '...)'
|
|
: 'No Signature'
|
|
)
|
|
),
|
|
]
|
|
),
|
|
]),
|
|
m('div', { style: { float: 'left', marginTop: '10px', marginBottom: '10px' } }, [
|
|
m('label[for=mtags]', 'Message Distribution: '),
|
|
m(
|
|
'select[id=mtags]',
|
|
{
|
|
value: selectedGroup,
|
|
onchange: (e) => {
|
|
selectedGroup = messageGroups[e.target.selectedIndex];
|
|
selectedGroupCode = messageGroupsCode[e.target.selectedIndex];
|
|
widget.popupMessage(m(createchannel, { authorId: vnode.attrs.authorId }));
|
|
},
|
|
},
|
|
[messageGroups.map((group) => m('option', { value: group }, group))]
|
|
),
|
|
]),
|
|
circles &&
|
|
m(
|
|
'div',
|
|
{
|
|
style: {
|
|
float: 'left',
|
|
marginTop: '10px',
|
|
marginBottom: '10px',
|
|
display: selectedGroupCode === util.EXTERNAL ? 'block' : 'none',
|
|
},
|
|
},
|
|
[
|
|
m('label[for=circlestag]', 'Circles: '),
|
|
m(
|
|
'select[id=circlestag]',
|
|
{
|
|
value: selectedCircle,
|
|
onchange: (e) => {
|
|
selectedCircle = circles[e.target.selectedIndex];
|
|
// selectedGroupCode = messageGroupsCode[e.target.selectedIndex];
|
|
},
|
|
},
|
|
[
|
|
circles.map((circle) =>
|
|
m('option', { value: circle.mGroupName }, circle.mGroupName)
|
|
),
|
|
]
|
|
),
|
|
]
|
|
),
|
|
m('textarea[rows=5][placeholder=Description]', {
|
|
style: { width: '100%', display: 'block' },
|
|
oninput: (e) => (body = e.target.value),
|
|
value: body,
|
|
}),
|
|
m(
|
|
'button',
|
|
{
|
|
onclick: async () => {
|
|
const res = await rs.rsJsonApiRequest('/rsgxschannels/createChannelV2', {
|
|
name: title,
|
|
description: body,
|
|
thumbnail: { mData: { base64: thumbnail } },
|
|
...(Number(identity) !== 0 && { authorId: identity }), // checks if some identity has to be assigned
|
|
circleType: selectedGroupCode,
|
|
...(selectedGroupCode === util.EXTERNAL &&
|
|
selectedCircle && { circleId: selectedCircle.mGroupId }), // checks if the selectedGroup code is EXTERNAL
|
|
});
|
|
if (res.body.retval) {
|
|
util.updatedisplaychannels(res.body.channelId);
|
|
m.redraw();
|
|
}
|
|
res.body.retval === false
|
|
? widget.popupMessage([m('h3', 'Error'), m('hr'), m('p', res.body.errorMessage)])
|
|
: widget.popupMessage([
|
|
m('h3', 'Success'),
|
|
m('hr'),
|
|
m('p', 'Channel created successfully'),
|
|
]);
|
|
},
|
|
},
|
|
'Create'
|
|
),
|
|
]),
|
|
};
|
|
}
|
|
|
|
const AddPost = () => {
|
|
let content = '';
|
|
let ptitle = '';
|
|
let pthumbnail = [];
|
|
let pfiles = [];
|
|
let uploadFiles = true;
|
|
return {
|
|
view: (vnode) =>
|
|
m('.widget', [
|
|
m('h3', 'Add Post'),
|
|
m('hr'),
|
|
m('label[for=thumbnail]', 'Thumbnail: '),
|
|
m('input[type=file][name=files][id=thumbnail][accept=image/*]', {
|
|
onchange: async (e) => {
|
|
const reader = new FileReader();
|
|
reader.onloadend = function () {
|
|
pthumbnail = reader.result.substring(reader.result.indexOf(',') + 1);
|
|
};
|
|
reader.readAsDataURL(e.target.files[0]); // converts into base64 string
|
|
},
|
|
}),
|
|
m('label[for=browse]', 'Attachments: '),
|
|
m('input[type=file][name=files][id=browse][multiple=multiple]', {
|
|
// attachments option wrong hash, not working
|
|
onchange: async (e) => {
|
|
uploadFiles = false;
|
|
filesUploadHashes.PostFiles = [];
|
|
pfiles = [];
|
|
for (let i = 0; i < e.target.files.length; i++) {
|
|
await parsefile(e.target.files[i], 'multiple');
|
|
}
|
|
// console.log(filesUploadHashes.PostFiles, filesUploadHashes.PostFiles.length);
|
|
|
|
if (filesUploadHashes.PostFiles.length === e.target.files.length) {
|
|
for (let i = 0; i < e.target.files.length; i++) {
|
|
pfiles.push({
|
|
name: e.target.files[i].name,
|
|
size: e.target.files[i].size,
|
|
hash: filesUploadHashes.PostFiles[i],
|
|
});
|
|
}
|
|
uploadFiles = true;
|
|
}
|
|
},
|
|
}),
|
|
m('input[type=text][placeholder=Title]', {
|
|
oninput: (e) => (ptitle = e.target.value),
|
|
}),
|
|
m('textarea[rows=5]', {
|
|
style: { width: '90%', display: 'block' },
|
|
oninput: (e) => (content = e.target.value),
|
|
value: content,
|
|
}),
|
|
m(
|
|
'button',
|
|
{
|
|
onclick: async () => {
|
|
if (uploadFiles) {
|
|
// console.log(vnode.attrs.chanId, ptitle, content, pfiles, pthumbnail);
|
|
const res = await rs.rsJsonApiRequest('/rsgxschannels/createPostV2', {
|
|
channelId: vnode.attrs.chanId,
|
|
title: ptitle,
|
|
mBody: content,
|
|
files: pfiles, // does not work for now
|
|
thumbnail: { mData: { base64: pthumbnail } },
|
|
});
|
|
res.body.retval === false
|
|
? widget.popupMessage([m('h3', 'Error'), m('hr'), m('p', res.body.errorMessage)])
|
|
: widget.popupMessage([
|
|
m('h3', 'Success'),
|
|
m('hr'),
|
|
m('p', 'Post added successfully'),
|
|
]);
|
|
util.updatedisplaychannels(vnode.attrs.chanId);
|
|
m.redraw();
|
|
}
|
|
},
|
|
},
|
|
'Add'
|
|
),
|
|
]),
|
|
};
|
|
};
|
|
|
|
const ChannelView = () => {
|
|
let cname = '';
|
|
let cimage = '';
|
|
let cauthor = '';
|
|
let csubscribed = {};
|
|
let mychannel = false;
|
|
let cposts = 0;
|
|
let plist = {};
|
|
let createDate = {};
|
|
let lastActivity = {};
|
|
return {
|
|
oninit: (v) => {
|
|
if (Data.DisplayChannels[v.attrs.id]) {
|
|
cname = Data.DisplayChannels[v.attrs.id].name;
|
|
cimage = Data.DisplayChannels[v.attrs.id].image;
|
|
if (rs.userList.userMap[Data.DisplayChannels[v.attrs.id].author]) {
|
|
cauthor = rs.userList.userMap[Data.DisplayChannels[v.attrs.id].author];
|
|
} else if (Number(Data.DisplayChannels[v.attrs.id].author) === 0) {
|
|
cauthor = 'No Contact Author';
|
|
} else {
|
|
cauthor = 'Unknown';
|
|
}
|
|
csubscribed = Data.DisplayChannels[v.attrs.id].isSubscribed;
|
|
mychannel = Data.DisplayChannels[v.attrs.id].mychannel;
|
|
cposts = Data.DisplayChannels[v.attrs.id].posts;
|
|
createDate = Data.DisplayChannels[v.attrs.id].created;
|
|
lastActivity = Data.DisplayChannels[v.attrs.id].activity;
|
|
}
|
|
if (Data.Posts[v.attrs.id]) {
|
|
plist = Data.Posts[v.attrs.id];
|
|
}
|
|
},
|
|
view: (v) => [
|
|
m(
|
|
'a[title=Back]',
|
|
{
|
|
onclick: () =>
|
|
m.route.set('/channels/:tab', {
|
|
tab: m.route.param().tab,
|
|
}),
|
|
},
|
|
m('i.fas.fa-arrow-left')
|
|
),
|
|
m('.widget__heading', [
|
|
m('h3', cname),
|
|
m(
|
|
'button',
|
|
{
|
|
onclick: async () => {
|
|
const res = await rs.rsJsonApiRequest('/rsgxschannels/subscribeToChannel', {
|
|
channelId: v.attrs.id,
|
|
subscribe: !csubscribed,
|
|
});
|
|
if (res.body.retval) {
|
|
csubscribed = !csubscribed;
|
|
Data.DisplayChannels[v.attrs.id].isSubscribed = csubscribed;
|
|
}
|
|
},
|
|
},
|
|
csubscribed ? 'Subscribed' : 'Subscribe'
|
|
),
|
|
]),
|
|
m('.widget__body', [
|
|
m('.media-item', [
|
|
m('.media-item__details', [
|
|
m('img', {
|
|
src:
|
|
cimage.mData.base64 === ''
|
|
? 'data/streaming.png'
|
|
: `data:image/png;base64,${cimage.mData.base64}`,
|
|
}),
|
|
m('.media-item__details-info', [
|
|
m('div', [m('b', 'Posts: '), m('span', cposts)]),
|
|
m('div', [
|
|
m('b', 'Date created: '),
|
|
m(
|
|
'span',
|
|
typeof createDate === 'object'
|
|
? new Date(createDate.xint64 * 1000).toLocaleString()
|
|
: 'Unknown'
|
|
),
|
|
]),
|
|
m('div', [m('b', 'Admin: '), m('span', cauthor)]),
|
|
m('div', [
|
|
m('b', 'Last activity: '),
|
|
m(
|
|
'span',
|
|
typeof lastActivity === 'object'
|
|
? new Date(lastActivity.xint64 * 1000).toLocaleString()
|
|
: 'Unknown'
|
|
),
|
|
]),
|
|
]),
|
|
]),
|
|
m('.media-item__desc', [
|
|
m('b', 'Description: '),
|
|
m('span', Data.DisplayChannels[v.attrs.id].description || 'No Description'),
|
|
]),
|
|
]),
|
|
m(
|
|
'.posts',
|
|
{
|
|
style: 'display: ' + (csubscribed ? 'flex' : 'none'),
|
|
},
|
|
[
|
|
m('.posts__heading', [
|
|
m('h3', 'Posts'),
|
|
mychannel &&
|
|
m(
|
|
'button',
|
|
{ onclick: () => widget.popupMessage(m(AddPost, { chanId: v.attrs.id })) },
|
|
['Add Post', m('i.fas.fa-edit')]
|
|
),
|
|
]),
|
|
m(
|
|
'.posts-container',
|
|
Object.keys(plist).map((key, index) => [
|
|
m(
|
|
'.posts-container-card',
|
|
{
|
|
style: 'display: ' + (plist[key].isSearched ? 'flex' : 'none'), // for search
|
|
onclick: () => {
|
|
m.route.set('/channels/:tab/:mGroupId/:mMsgId', {
|
|
tab: m.route.param().tab,
|
|
mGroupId: v.attrs.id,
|
|
mMsgId: key,
|
|
});
|
|
},
|
|
},
|
|
[
|
|
m('img', {
|
|
src:
|
|
plist[key].post.mThumbnail.mData.base64 === ''
|
|
? 'data/streaming.png'
|
|
: 'data:image/png;base64,' + plist[key].post.mThumbnail.mData.base64,
|
|
alt: 'No Thumbnail',
|
|
}),
|
|
m('p', plist[key].post.mMeta.mMsgName),
|
|
]
|
|
),
|
|
])
|
|
),
|
|
]
|
|
),
|
|
]),
|
|
],
|
|
};
|
|
};
|
|
|
|
async function addvote(voteType, vchannelId, vpostId, vauthorId, vcommentId) {
|
|
const res = await rs.rsJsonApiRequest('/rsgxschannels/voteForComment', {
|
|
channelId: vchannelId,
|
|
postId: vpostId,
|
|
authorId: vauthorId,
|
|
commentId: vcommentId,
|
|
vote: voteType,
|
|
});
|
|
if (res.body.retval) {
|
|
util.updatedisplaychannels(vchannelId);
|
|
m.redraw();
|
|
}
|
|
}
|
|
|
|
const AddComment = () => {
|
|
let inputComment = '';
|
|
let identity;
|
|
return {
|
|
oninit: (vnode) => {
|
|
if (vnode.attrs.authorId) {
|
|
identity = vnode.attrs.authorId[0];
|
|
}
|
|
},
|
|
view: (vnode) =>
|
|
m('.widget', [
|
|
m('h3', 'Add Comment'),
|
|
m('label[for=tags]', 'Select identity'),
|
|
m(
|
|
'select[id=idtags]',
|
|
{
|
|
value: identity,
|
|
onchange: (e) => {
|
|
identity = vnode.attrs.authorId[e.target.selectedIndex];
|
|
},
|
|
},
|
|
[
|
|
vnode.attrs.authorId &&
|
|
vnode.attrs.authorId.map((o) =>
|
|
m(
|
|
'option',
|
|
{ value: o },
|
|
rs.userList.userMap[o].toLocaleString() + ' (' + o.slice(0, 8) + '...)'
|
|
)
|
|
),
|
|
]
|
|
),
|
|
m('hr'),
|
|
(vnode.attrs.parent_comment !== '') > 0
|
|
? [m('h5', 'Reply to comment: '), m('p', vnode.attrs.parent_comment)] // if it is add reply option
|
|
: '',
|
|
m('textarea[rows=5]', {
|
|
style: { width: '90%', display: 'block' },
|
|
oninput: (e) => (inputComment = e.target.value),
|
|
value: inputComment,
|
|
}),
|
|
m(
|
|
'button',
|
|
{
|
|
onclick: async () => {
|
|
const res = await rs.rsJsonApiRequest('/rsgxschannels/createCommentV2', {
|
|
channelId: vnode.attrs.channelId,
|
|
threadId: vnode.attrs.threadId,
|
|
comment: inputComment,
|
|
authorId: identity,
|
|
parentId: vnode.attrs.parentId,
|
|
});
|
|
|
|
res.body.retval === false
|
|
? widget.popupMessage([m('h3', 'Error'), m('hr'), m('p', res.body.errorMessage)])
|
|
: widget.popupMessage([
|
|
m('h3', 'Success'),
|
|
m('hr'),
|
|
m('p', 'Comment added successfully'),
|
|
]);
|
|
util.updatedisplaychannels(vnode.attrs.channelId);
|
|
m.redraw();
|
|
},
|
|
},
|
|
'Add'
|
|
),
|
|
]),
|
|
};
|
|
};
|
|
function displaycomment() {
|
|
// recursive function to display comments
|
|
return {
|
|
oninit: (v) => {},
|
|
view: ({ attrs: { commentStruct, identity, replyDepth, voteIdentity } }) => {
|
|
const comment = commentStruct.comment;
|
|
let cUpVotes = 0;
|
|
let cDownVotes = 0;
|
|
let parMap = {};
|
|
if (Data.ParentCommentMap[comment.mMeta.mMsgId]) {
|
|
parMap = Data.ParentCommentMap[comment.mMeta.mMsgId];
|
|
}
|
|
if (
|
|
Data.Votes[comment.mMeta.mThreadId] &&
|
|
Data.Votes[comment.mMeta.mThreadId][comment.mMeta.mMsgId]
|
|
) {
|
|
cUpVotes = Data.Votes[comment.mMeta.mThreadId][comment.mMeta.mMsgId].upvotes;
|
|
cDownVotes = Data.Votes[comment.mMeta.mThreadId][comment.mMeta.mMsgId].downvotes;
|
|
}
|
|
return [
|
|
m('tr', [
|
|
Object.keys(parMap).length // if it has replies
|
|
? m(
|
|
'td',
|
|
m('i.fas.fa-angle-right', {
|
|
class: 'fa-rotate-' + (commentStruct.showReplies ? '90' : '0'),
|
|
style: 'cursor:pointer',
|
|
onclick: () => {
|
|
commentStruct.showReplies = !commentStruct.showReplies;
|
|
},
|
|
})
|
|
)
|
|
: m('td', ''),
|
|
|
|
m(
|
|
'td',
|
|
{
|
|
style: {
|
|
position: 'relative',
|
|
'--replyDepth': replyDepth,
|
|
left: 'calc(30px*var(--replyDepth))', // shifts the reply by 30px
|
|
},
|
|
},
|
|
[
|
|
comment.mComment,
|
|
m('options', { style: 'display:block' }, [
|
|
m(
|
|
'button',
|
|
{
|
|
style: 'font-size:15px',
|
|
onclick: () =>
|
|
widget.popupMessage(
|
|
m(AddComment, {
|
|
parent_comment: comment.mComment,
|
|
channelId: comment.mMeta.mGroupId,
|
|
authorId: identity,
|
|
threadId: comment.mMeta.mThreadId,
|
|
parentId: comment.mMeta.mMsgId,
|
|
})
|
|
),
|
|
},
|
|
'Reply'
|
|
),
|
|
voteIdentity &&
|
|
m(
|
|
'button',
|
|
{
|
|
style: 'font-size:15px',
|
|
onclick: () =>
|
|
addvote(
|
|
util.GXS_VOTE_UP,
|
|
comment.mMeta.mGroupId,
|
|
comment.mMeta.mThreadId,
|
|
voteIdentity,
|
|
comment.mMeta.mMsgId
|
|
),
|
|
},
|
|
m('i.fas.fa-thumbs-up')
|
|
),
|
|
voteIdentity &&
|
|
m(
|
|
'button',
|
|
{
|
|
style: 'font-size:15px',
|
|
onclick: () =>
|
|
addvote(
|
|
util.GXS_VOTE_DOWN,
|
|
comment.mMeta.mGroupId,
|
|
comment.mMeta.mThreadId,
|
|
voteIdentity,
|
|
comment.mMeta.mMsgId
|
|
),
|
|
},
|
|
m('i.fas.fa-thumbs-down')
|
|
),
|
|
]),
|
|
]
|
|
),
|
|
|
|
m('td', rs.userList.userMap[comment.mMeta.mAuthorId]),
|
|
m(
|
|
'td',
|
|
typeof comment.mMeta.mPublishTs === 'object'
|
|
? new Date(comment.mMeta.mPublishTs.xint64 * 1000).toLocaleString()
|
|
: 'undefined'
|
|
),
|
|
m('td', comment.mScore),
|
|
m('td', cUpVotes),
|
|
m('td', cDownVotes),
|
|
]),
|
|
commentStruct.showReplies && // recursive calls for the replies
|
|
// parMap.map((value) =>
|
|
Object.keys(parMap).map((key, index) =>
|
|
m(displaycomment, {
|
|
commentStruct: Data.Comments[parMap[key].mMeta.mThreadId][parMap[key].mMeta.mMsgId],
|
|
voteIdentity,
|
|
identity,
|
|
replyDepth: replyDepth + 1, // for the css
|
|
})
|
|
),
|
|
];
|
|
},
|
|
};
|
|
}
|
|
|
|
const PostView = () => {
|
|
let post = {};
|
|
let topComments = {};
|
|
const filesInfo = {};
|
|
let voteIdentity;
|
|
let ownId;
|
|
return {
|
|
oninit: async (v) => {
|
|
if (Data.Posts[v.attrs.channelId] && Data.Posts[v.attrs.channelId][v.attrs.msgId]) {
|
|
post = Data.Posts[v.attrs.channelId][v.attrs.msgId].post;
|
|
}
|
|
if (Data.TopComments[v.attrs.msgId]) {
|
|
topComments = Data.TopComments[v.attrs.msgId]; // get all the top level parent comments
|
|
}
|
|
if (post) {
|
|
post.mFiles.map(async (file) => {
|
|
const res = await rs.rsJsonApiRequest('/rsfiles/alreadyHaveFile', {
|
|
// checks if the file is already there with the user
|
|
hash: file.mHash,
|
|
});
|
|
filesInfo[file.mHash] = res.body;
|
|
});
|
|
}
|
|
await peopleUtil.ownIds((data) => {
|
|
ownId = data;
|
|
for (let i = 0; i < ownId.length; i++) {
|
|
if (Number(ownId[i]) === 0) {
|
|
ownId.splice(i, 1); // workaround for id '0'
|
|
}
|
|
}
|
|
voteIdentity = ownId[0];
|
|
});
|
|
fileDown.Downloads.loadStatus(); // for retrieving downloading files.
|
|
},
|
|
view: (v) => [
|
|
m(
|
|
'a[title=Back]',
|
|
{
|
|
onclick: () =>
|
|
m.route.set('/channels/:tab/:mGroupId', {
|
|
tab: m.route.param().tab,
|
|
mGroupId: m.route.param().mGroupId,
|
|
}),
|
|
},
|
|
m('i.fas.fa-arrow-left')
|
|
),
|
|
m('.widget__heading', m('h3', post.mMeta.mMsgName)),
|
|
m('.widget__body', [
|
|
m('p', { style: { whiteSpace: 'normal' } }, m.trust(post.mMsg)),
|
|
m('.file-section', [
|
|
m('h3', 'Files(' + post.mAttachmentCount + ')'),
|
|
m(
|
|
util.FilesTable,
|
|
m(
|
|
'tbody',
|
|
post.mFiles.map((file) =>
|
|
m('tr', [
|
|
m('td', file.mName),
|
|
m('td', rs.formatBytes(file.mSize.xint64)),
|
|
m(
|
|
'button',
|
|
{
|
|
style: { fontSize: '0.9em' },
|
|
onclick: async () =>
|
|
widget.popupMessage([
|
|
m('p', 'Start Download?'),
|
|
m(
|
|
'button',
|
|
{
|
|
onclick: async () => {
|
|
if (filesInfo[file.mHash] && !filesInfo[file.mHash].retval) {
|
|
const res = await rs.rsJsonApiRequest('/rsFiles/FileRequest', {
|
|
fileName: file.mName,
|
|
hash: file.mHash,
|
|
flags: util.RS_FILE_REQ_ANONYMOUS_ROUTING,
|
|
size: {
|
|
xstr64: file.mSize.xstr64,
|
|
},
|
|
});
|
|
res.body.retval === false
|
|
? widget.popupMessage([
|
|
m('h3', 'Error'),
|
|
m('hr'),
|
|
m('p', res.body.errorMessage),
|
|
])
|
|
: widget.popupMessage([
|
|
m('h3', 'Success'),
|
|
m('hr'),
|
|
m('p', 'Download Started'),
|
|
]);
|
|
m.redraw();
|
|
}
|
|
},
|
|
},
|
|
'Start Download'
|
|
),
|
|
]),
|
|
},
|
|
filesInfo[file.mHash]
|
|
? filesInfo[file.mHash].retval
|
|
? 'Open File'
|
|
: ['Download', m('i.fas.fa-download')]
|
|
: 'Please Wait...'
|
|
),
|
|
fileDown.list[file.mHash] && // using the file from files_util to display download.
|
|
m(fileUtil.File, {
|
|
info: fileDown.list[file.mHash],
|
|
direction: 'down',
|
|
transferred: fileDown.list[file.mHash].transfered.xint64,
|
|
parts: [],
|
|
}),
|
|
])
|
|
)
|
|
)
|
|
),
|
|
]),
|
|
m('.comments-section', [
|
|
m('h3', 'Comments'),
|
|
m('.comments-section__menu', [
|
|
m(
|
|
'button',
|
|
{
|
|
onclick: () => {
|
|
widget.popupMessage(
|
|
m(AddComment, {
|
|
parent_comment: '',
|
|
channelId: v.attrs.channelId,
|
|
authorId: ownId,
|
|
threadId: v.attrs.msgId,
|
|
parentId: v.attrs.msgId,
|
|
})
|
|
);
|
|
},
|
|
},
|
|
'Add Comment'
|
|
),
|
|
m('.comments-section__menu-id', [
|
|
m('label[for=idtags', 'Voter ID: '),
|
|
m(
|
|
'select[id=idtags]',
|
|
{
|
|
value: voteIdentity,
|
|
onchange: (e) => {
|
|
voteIdentity = ownId[e.target.selectedIndex];
|
|
},
|
|
},
|
|
[
|
|
ownId &&
|
|
ownId.map((o) =>
|
|
m(
|
|
'option',
|
|
{ value: o },
|
|
`${rs.userList.userMap[o].toLocaleString()} (${o.slice(0, 8)}...)`
|
|
)
|
|
),
|
|
]
|
|
),
|
|
]),
|
|
]),
|
|
]),
|
|
m(
|
|
util.CommentsTable,
|
|
m(
|
|
'tbody',
|
|
Object.keys(topComments).map((key, index) =>
|
|
Data.Comments[topComments[key].mMeta.mThreadId] &&
|
|
Data.Comments[topComments[key].mMeta.mThreadId][topComments[key].mMeta.mMsgId]
|
|
? m(displaycomment, {
|
|
// calls the recursive function for all the parents.
|
|
identity: ownId,
|
|
voteIdentity,
|
|
commentStruct:
|
|
Data.Comments[topComments[key].mMeta.mThreadId][
|
|
topComments[key].mMeta.mMsgId
|
|
],
|
|
replyDepth: 0,
|
|
})
|
|
: ''
|
|
)
|
|
)
|
|
),
|
|
]),
|
|
],
|
|
};
|
|
};
|
|
|
|
module.exports = {
|
|
ChannelView,
|
|
PostView,
|
|
createchannel,
|
|
};
|