sbot/ui/lib/com/pm-form.js

202 lines
6.0 KiB
JavaScript

'use strict'
var h = require('hyperscript')
var suggestBox = require('suggest-box')
var schemas = require('ssb-msg-schemas')
var refs = require('ssb-ref')
var createHash = require('multiblob/util').createHash
var pull = require('pull-stream')
var pushable = require('pull-pushable')
var app = require('../app')
var ui = require('../ui')
var modals = require('../ui/modals')
var com = require('./index')
var util = require('../util')
var markdown = require('../markdown')
var mentionslib = require('../mentions')
var social = require('../social-graph')
module.exports = function (opts, h2) {
h = h2 || h
var recipients = []
var placeholder = (opts && opts.placeholder) ? opts.placeholder : ''
// make sure there are no name conflicts first
var conflicts = []
for (var k in app.actionItems) {
var item = app.actionItems[k]
if (item.type == 'name-conflict') {
conflicts.push(h('.note.warning',
h('h3', 'Heads up!'),
h('p', 'You are following more than one user named "'+item.name+'." You need to rename one of them before you send secret messages, to avoid confusion.'),
h('ul.list-inline', item.ids.map(function (id) { return h('li', com.userImg(id), ' ', com.user(id)) }))
))
}
}
if (conflicts.length)
return h('.notifications', { style: 'margin-top: 24px' }, conflicts)
// markup
var recpInput = h('input', { onsuggestselect: onSelectRecipient, onkeydown: onRecpInputKeydown })
var recipientsEl = h('.pm-form-recipients', h('span.recp-label', 'To'), recpInput)
var textarea = h('textarea', { name: 'text', placeholder: placeholder, onkeyup: onTextChange })
var postBtn = h('button.postbtn.btn', { disabled: true }, 'Send')
suggestBox(textarea, app.suggestOptions)
suggestBox(recpInput, { any: app.suggestOptions['@'] }, { cls: 'msg-recipients' })
renderRecpList()
if (opts && opts.recipients)
opts.recipients.forEach(addRecp)
var form = h('form.pm-form', { onsubmit: post },
recipientsEl,
h('.pm-form-textarea', textarea),
h('.pm-form-attachments', postBtn)
)
function disable () {
postBtn.setAttribute('disabled', true)
}
function enable () {
postBtn.removeAttribute('disabled')
}
function renderRecpList () {
// remove all .recp
Array.prototype.forEach.call(recipientsEl.querySelectorAll('.recp'), function (el) {
recipientsEl.removeChild(el)
})
// render
recipients.forEach(function (id) {
recipientsEl.insertBefore(h('.recp',
com.icon('lock'),
' ',
com.userName(id),
' ',
h('a', { href: '#', onclick: onRemoveRecipient, 'data-id': id, innerHTML: '×', tabIndex: '-1' })
), recpInput)
})
resizeTextarea()
}
// handlers
function onTextChange (e) {
if (recipients.length && textarea.value.trim())
enable()
else
disable()
}
function addRecp (id) {
// enforce limit
if (recipients.length >= 7) {
ui.notice('warning', 'Cannot add @'+com.userName(id)+' - You have reached the limit of 7 recipients on a Secret Message.')
recpInput.value = ''
return
}
// warn if the recipient doesnt follow the current user
if (id !== app.user.id && !social.follows(id, app.user.id))
ui.notice('warning', 'Warning: @'+com.userName(id)+' does not follow you, and may not receive your message.')
// remove if already exists (we'll push to end of list so user sees its there)
var i = recipients.indexOf(id)
if (i !== -1)
recipients.splice(i, 1)
// add, render
recipients.push(id)
recpInput.value = ''
renderRecpList()
}
function onSelectRecipient (e) {
addRecp(e.detail.id)
}
function onRemoveRecipient (e) {
e.preventDefault()
var i = recipients.indexOf(e.target.dataset.id)
if (i !== -1) {
recipients.splice(i, 1)
renderRecpList()
recpInput.focus()
}
}
function onRecpInputKeydown (e) {
// backspace on an empty field?
if (e.keyCode == 8 && recpInput.value == '' && recipients.length) {
recipients.pop()
renderRecpList()
}
}
// dynamically sizes the textarea based on available space
// (no css method, including flexbox, would really nail this one)
function resizeTextarea () {
try {
var height = 400 - 4
height -= recipientsEl.getClientRects()[0].height
height -= form.querySelector('.pm-form-attachments').getClientRects()[0].height
textarea.style.height = height + 'px'
} catch (e) {
// ignore, probably havent rendered yet
}
}
function post (e) {
e.preventDefault()
var text = textarea.value
if (!text.trim())
return
disable()
ui.pleaseWait(true)
// prep text
mentionslib.extract(text, function (err, mentions) {
if (err) {
ui.setStatus(null)
ui.pleaseWait(false)
enable()
if (err.conflict)
modals.error('Error While Publishing', 'You follow multiple people with the name "'+err.name+'." Go to the homepage to resolve this before publishing.')
else
modals.error('Error While Publishing', err, 'This error occured while trying to extract the mentions from a secret message text.')
return
}
// make sure the user is in the recipients
if (recipients.indexOf(app.user.id) === -1)
recipients.push(app.user.id)
// list recipients with their names
var recps = recipients.map(function (id) {
return { link: id, name: com.userName(id) }
})
// publish
var post = schemas.post(text, null, null, mentions, recps)
app.ssb.private.publish(post, recipients, function (err, msg) {
ui.setStatus(null)
enable()
ui.pleaseWait(false)
if (err) modals.error('Error While Publishing', err, 'This error occured while trying to private-publish a new secret message.')
else {
app.ssb.patchwork.subscribe(msg.key)
app.ssb.patchwork.markRead(msg.key)
opts && opts.onpost && opts.onpost(msg)
}
})
})
}
return form
}