#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'); }); } } };