386 lines
13 KiB
JavaScript
386 lines
13 KiB
JavaScript
#include csrfp.js
|
|
#include msgbox.js
|
|
#include utility.js
|
|
#include messages/actbtn.js
|
|
#include messages/list.js
|
|
#include messages/recipient.js
|
|
#include messages/reply.jsx
|
|
#include messages/thread.js
|
|
|
|
const MszMessages = () => {
|
|
const extractMsgIds = msg => {
|
|
if(typeof msg.getId === 'function')
|
|
return msg.getId();
|
|
if(typeof msg.toString === 'function')
|
|
return msg.toString();
|
|
throw 'unsupported message type';
|
|
};
|
|
|
|
const displayErrorMessage = async error => {
|
|
let text;
|
|
if(typeof error === 'string')
|
|
text = error;
|
|
else if(typeof error.text === 'string')
|
|
text = error.text;
|
|
else if(typeof error.toString === 'function')
|
|
text = error.toString();
|
|
else
|
|
text = 'Something indescribable happened.';
|
|
|
|
await MszShowMessageBox(text, 'Error');
|
|
return false;
|
|
};
|
|
|
|
const msgsCreate = async (title, text, parser, draft, recipient, replyTo) => {
|
|
const formData = new FormData;
|
|
formData.append('_csrfp', MszCSRFP.getToken());
|
|
formData.append('title', title);
|
|
formData.append('body', text);
|
|
formData.append('parser', parser);
|
|
formData.append('draft', draft);
|
|
formData.append('recipient', recipient);
|
|
formData.append('reply', replyTo);
|
|
|
|
const result = await $x.post('/messages/create', { type: 'json' }, formData);
|
|
|
|
MszCSRFP.setFromHeaders(result);
|
|
|
|
const body = result.body();
|
|
if(body.error !== undefined)
|
|
throw body.error;
|
|
|
|
return body;
|
|
};
|
|
|
|
const msgsUpdate = async (messageId, title, text, parser, draft) => {
|
|
const formData = new FormData;
|
|
formData.append('_csrfp', MszCSRFP.getToken());
|
|
formData.append('title', title);
|
|
formData.append('body', text);
|
|
formData.append('parser', parser);
|
|
formData.append('draft', draft);
|
|
|
|
const result = await $x.post(`/messages/${encodeURIComponent(messageId)}`, { type: 'json' }, formData);
|
|
|
|
MszCSRFP.setFromHeaders(result);
|
|
|
|
const body = result.body();
|
|
if(body.error !== undefined)
|
|
throw body.error;
|
|
|
|
return body;
|
|
};
|
|
|
|
const msgsMark = async (msgs, state) => {
|
|
const result = await $x.post('/messages/mark', { type: 'json' }, {
|
|
_csrfp: MszCSRFP.getToken(),
|
|
type: state,
|
|
messages: msgs.map(extractMsgIds).join(','),
|
|
});
|
|
|
|
MszCSRFP.setFromHeaders(result);
|
|
|
|
const body = result.body();
|
|
if(body.error !== undefined)
|
|
throw body.error;
|
|
|
|
return true;
|
|
};
|
|
|
|
const msgsDelete = async msgs => {
|
|
const result = await $x.post('/messages/delete', { type: 'json' }, {
|
|
_csrfp: MszCSRFP.getToken(),
|
|
messages: msgs.map(extractMsgIds).join(','),
|
|
});
|
|
|
|
MszCSRFP.setFromHeaders(result);
|
|
|
|
const body = result.body();
|
|
if(body.error !== undefined)
|
|
throw body.error;
|
|
|
|
return true;
|
|
};
|
|
|
|
const msgsRestore = async msgs => {
|
|
const result = await $x.post('/messages/restore', { type: 'json' }, {
|
|
_csrfp: MszCSRFP.getToken(),
|
|
messages: msgs.map(extractMsgIds).join(','),
|
|
});
|
|
|
|
MszCSRFP.setFromHeaders(result);
|
|
|
|
const body = result.body();
|
|
if(body.error !== undefined)
|
|
throw body.error;
|
|
|
|
return true;
|
|
};
|
|
|
|
const msgsNuke = async msgs => {
|
|
const result = await $x.post('/messages/nuke', { type: 'json' }, {
|
|
_csrfp: MszCSRFP.getToken(),
|
|
messages: msgs.map(extractMsgIds).join(','),
|
|
});
|
|
|
|
MszCSRFP.setFromHeaders(result);
|
|
|
|
const body = result.body();
|
|
if(body.error !== undefined)
|
|
throw body.error;
|
|
|
|
return true;
|
|
};
|
|
|
|
const msgsUserBtns = Array.from($qa('.js-header-pms-button'));
|
|
if(msgsUserBtns.length > 0)
|
|
$x.get('/messages/stats', { type: 'json' }).then(result => {
|
|
const body = result.body();
|
|
if(typeof body === 'object' && typeof body.unread === 'number')
|
|
if(body.unread > 0)
|
|
for(const msgsUserBtn of msgsUserBtns)
|
|
msgsUserBtn.append($e({ child: body.unread.toLocaleString(), attrs: { className: 'header__desktop__user__button__count' } }));
|
|
});
|
|
|
|
const msgsListElem = $q('.js-messages-list');
|
|
const msgsList = msgsListElem instanceof Element ? new MsgMessagesList(msgsListElem) : undefined;
|
|
|
|
const msgsListEmptyNotice = $q('.js-messages-folder-empty');
|
|
|
|
const msgsThreadElem = $q('.js-messages-thread');
|
|
const msgsThread = msgsThreadElem instanceof Element ? new MszMessagesThread(msgsThreadElem) : undefined;
|
|
|
|
const msgsRecipientElem = $q('.js-messages-recipient');
|
|
const msgsRecipient = msgsRecipientElem instanceof Element ? new MszMessagesRecipient(msgsRecipientElem) : undefined;
|
|
|
|
const msgsReplyElem = $q('.js-messages-reply');
|
|
const msgsReply = msgsReplyElem instanceof Element ? new MszMessagesReply(msgsReplyElem) : undefined;
|
|
|
|
if(msgsReply !== undefined) {
|
|
if(msgsRecipient !== undefined)
|
|
msgsRecipient.onUpdate(async info => {
|
|
msgsReply.setRecipient(typeof info.id === 'string' ? info.id : '');
|
|
msgsReply.setWarning(info.ban ? `${(typeof info.name === 'string' ? info.name : 'This user')} has been banned and will be unable to respond to your messages.` : undefined);
|
|
});
|
|
|
|
msgsReply.onSubmit(async form => {
|
|
try {
|
|
let result;
|
|
if(typeof form.message === 'string') {
|
|
result = await msgsUpdate(
|
|
form.message,
|
|
form.title,
|
|
form.body,
|
|
form.parser,
|
|
form.draft
|
|
);
|
|
} else {
|
|
result = await msgsCreate(
|
|
form.title,
|
|
form.body,
|
|
form.parser,
|
|
form.draft,
|
|
form.recipient,
|
|
form.reply || ''
|
|
);
|
|
}
|
|
|
|
if(typeof result.url === 'string')
|
|
location.assign(result.url);
|
|
} catch(ex) {
|
|
return await displayErrorMessage(ex);
|
|
}
|
|
});
|
|
}
|
|
|
|
let actSelectAll, actMarkRead, actMoveTrash, actNuke;
|
|
|
|
const actSelectAllBtn = $q('.js-messages-actions-select-all');
|
|
if(actSelectAllBtn instanceof Element) {
|
|
actSelectAll = new MszMessagesActionButton(actSelectAllBtn);
|
|
|
|
if(msgsList !== undefined) {
|
|
actSelectAll.setAction(async state => {
|
|
msgsList.setAllSelected(!state);
|
|
return !state;
|
|
});
|
|
msgsList.onSelectedChange((selectedNo, itemNo) => {
|
|
actSelectAll.setState(selectedNo >= itemNo);
|
|
});
|
|
actSelectAll.setState(msgsList.getAllSelected());
|
|
}
|
|
}
|
|
|
|
const actMarkReadBtn = $q('.js-messages-actions-mark-read');
|
|
if(actMarkReadBtn instanceof Element) {
|
|
actMarkRead = new MszMessagesActionButton(actMarkReadBtn);
|
|
|
|
if(msgsList !== undefined) {
|
|
msgsList.onSelectedChange(selectedNo => {
|
|
const enabled = selectedNo > 0;
|
|
actMarkRead.setEnabled(enabled);
|
|
|
|
if(enabled) {
|
|
const items = msgsList.getSelectedItems();
|
|
let readNo = 0, unreadNo = 0;
|
|
|
|
for(const item of items) {
|
|
if(item.isRead())
|
|
++readNo;
|
|
else
|
|
++unreadNo;
|
|
}
|
|
|
|
actMarkRead.setState(readNo > unreadNo);
|
|
}
|
|
});
|
|
actMarkRead.setAction(async state => {
|
|
const items = msgsList.getSelectedItems();
|
|
|
|
const result = await actMarkRead.disableWith(async () => {
|
|
try {
|
|
return await msgsMark(items, state ? 'unread' : 'read');
|
|
} catch(ex) {
|
|
return await displayErrorMessage(ex);
|
|
}
|
|
});
|
|
|
|
if(result) {
|
|
state = !state;
|
|
|
|
for(const item of items)
|
|
item.setRead(state);
|
|
|
|
return state;
|
|
}
|
|
});
|
|
} else if(msgsThread !== undefined) {
|
|
actMarkRead.setAction(async state => {
|
|
const items = [msgsThread.getMessage()];
|
|
|
|
const result = await actMarkRead.disableWith(async () => {
|
|
try {
|
|
return await msgsMark(items, state ? 'unread' : 'read');
|
|
} catch(ex) {
|
|
return await displayErrorMessage(ex);
|
|
}
|
|
});
|
|
|
|
return result ? !state : state;
|
|
});
|
|
}
|
|
}
|
|
|
|
const actMoveTrashBtn = $q('.js-messages-actions-move-trash');
|
|
if(actMoveTrashBtn instanceof Element) {
|
|
actMoveTrash = new MszMessagesActionButton(actMoveTrashBtn);
|
|
|
|
if(msgsList !== undefined) {
|
|
msgsList.onSelectedChange(selectedNo => actMoveTrash.setEnabled(selectedNo > 0));
|
|
actMoveTrash.setAction(async state => {
|
|
const items = msgsList.getSelectedItems();
|
|
|
|
if(!state && !await MszShowConfirmBox(`Are you sure you wish to delete ${items.length} item${items.length === 1 ? '' : 's'}?`, 'Confirmation'))
|
|
return;
|
|
|
|
const result = await actMoveTrash.disableWith(async () => {
|
|
try {
|
|
if(state)
|
|
return await msgsRestore(items);
|
|
return await msgsDelete(items);
|
|
} catch(ex) {
|
|
return await displayErrorMessage(ex);
|
|
}
|
|
});
|
|
|
|
if(result)
|
|
for(const message of items)
|
|
msgsList.removeItem(message);
|
|
|
|
if(msgsListEmptyNotice instanceof Element)
|
|
msgsListEmptyNotice.hidden = msgsList.getItemsCount() > 0;
|
|
});
|
|
} else if(msgsThread !== undefined) {
|
|
actMoveTrash.setAction(async state => {
|
|
if(!state && !await MszShowConfirmBox('Are you sure you wish to delete this message?', 'Confirmation'))
|
|
return;
|
|
|
|
const items = [msgsThread.getMessage()];
|
|
|
|
const result = await actMoveTrash.disableWith(async () => {
|
|
try {
|
|
if(state)
|
|
return await msgsRestore(items);
|
|
return await msgsDelete(items);
|
|
} catch(ex) {
|
|
return await displayErrorMessage(ex);
|
|
}
|
|
});
|
|
|
|
if(result) {
|
|
state = !state;
|
|
|
|
if(msgsReply !== undefined)
|
|
msgsReply.setHidden(state);
|
|
|
|
const msg = msgsThread.getMessage();
|
|
if(msg !== undefined)
|
|
msg.setDeleted(state);
|
|
|
|
return state;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
const actNukeBtn = $q('.js-messages-actions-nuke');
|
|
if(actNukeBtn instanceof Element) {
|
|
actNuke = new MszMessagesActionButton(actNukeBtn, true);
|
|
|
|
if(msgsList !== undefined) {
|
|
msgsList.onSelectedChange(selectedNo => actNuke.setEnabled(selectedNo > 0));
|
|
actNuke.setAction(async () => {
|
|
const items = msgsList.getSelectedItems();
|
|
|
|
if(!await MszShowConfirmBox(`Are you sure you wish to PERMANENTLY delete ${items.length} item${items.length === 1 ? '' : 's'}?`, 'Confirmation'))
|
|
return;
|
|
|
|
const result = await actNuke.disableWith(async () => {
|
|
try {
|
|
return await msgsNuke(items);
|
|
} catch(ex) {
|
|
return await displayErrorMessage(ex);
|
|
}
|
|
});
|
|
|
|
if(result)
|
|
for(const message of items)
|
|
msgsList.removeItem(message);
|
|
|
|
if(msgsListEmptyNotice instanceof Element)
|
|
msgsListEmptyNotice.hidden = msgsList.getItemsCount() > 0;
|
|
});
|
|
} else if(msgsThread !== undefined) {
|
|
actMoveTrash.watchState(state => {
|
|
actNuke.setHidden(!state);
|
|
});
|
|
actNuke.setAction(async () => {
|
|
if(!await MszShowConfirmBox('Are you sure you wish to PERMANENTLY delete this message?', 'Confirmation'))
|
|
return;
|
|
|
|
const items = [msgsThread.getMessage()];
|
|
|
|
const result = await actNuke.disableWith(async () => {
|
|
try {
|
|
return await msgsNuke(items);
|
|
} catch(ex) {
|
|
return await displayErrorMessage(ex);
|
|
}
|
|
});
|
|
|
|
if(result)
|
|
location.assign('/messages');
|
|
});
|
|
}
|
|
}
|
|
};
|