define([ 'jquery', '/bower_components/chainpad-crypto/crypto.js', '/common/curve.js' ], function ($, Crypto, Curve) { var Msg = {}; var Types = { message: 'MSG', update: 'UPDATE', unfriend: 'UNFRIEND' }; // TODO: pin the chat channel! // TODO: new Types // - send a rename message to the chat // - petnames // - close a chat / remove a friend // TODO // - mute a channel (hide notifications or don't open it?) // var pending = {}; var createData = Msg.createData = function (common, hash) { var proxy = common.getProxy(); return { channel: hash || common.createChannelId(), displayName: proxy[common.displayNameKey], profile: proxy.profile && proxy.profile.view, edPublic: proxy.edPublic, curvePublic: proxy.curvePublic, avatar: proxy.profile && proxy.profile.avatar }; }; var getFriend = function (common, pubkey) { var proxy = common.getProxy(); if (pubkey === proxy.edPublic) { var data = createData(common); delete data.channel; return data; } return proxy.friends ? proxy.friends[pubkey] : undefined; }; var removeFromFriendList = Msg.removeFromFriendList = function (common, edPublic, cb) { var proxy = common.getProxy(); if (!proxy.friends) { return; } var friends = proxy.friends; delete friends[edPublic]; common.whenRealtimeSyncs(common.getRealtime(), cb); }; var getFriendList = Msg.getFriendList = function (common) { var proxy = common.getProxy(); return proxy.friends || {}; }; Msg.getFriendChannelsList = function (common) { var friends = getFriendList(common); var list = []; Object.keys(friends).forEach(function (key) { list.push(friends[key].channel); }); return list; }; // Messaging tools var avatars = {}; Msg.getFriendListUI = function (common, open, remove) { var proxy = common.getProxy(); var $block = $('
'); var friends = proxy.friends || {}; Object.keys(friends).forEach(function (f) { var data = friends[f]; var $friend = $('
', {'class': 'friend avatar'}).appendTo($block); $friend.data('key', f); var $rightCol = $('', {'class': 'right-col'}); $('', {'class': 'name'}).text(data.displayName).appendTo($rightCol); var $remove = $('', {'class': 'remove fa fa-user-times'}).appendTo($rightCol); $friend.dblclick(function () { if (data.profile) { window.open('/profile/#' + data.profile); } }); $friend.click(function () { open(data.edPublic); }); $remove.click(function (e) { e.stopPropagation(); common.confirm("TODO: Are you sure?", function (yes) { if (!yes) { return; } remove(data.edPublic); }); }); if (data.avatar && avatars[data.avatar]) { $friend.append(avatars[data.avatar]); $friend.append($rightCol); } else { common.displayAvatar($friend, data.avatar, data.displayName, function ($img) { if (data.avatar && $img) { avatars[data.avatar] = $img[0].outerHTML; } $friend.append($rightCol); }); } }); return $block; }; Msg.createOwnedChannel = function (common, channelId, validateKey, owners, cb) { var network = common.getNetwork(); network.join(channelId).then(function (wc) { var cfg = { validateKey: validateKey, owners: owners }; var msg = ['GET_HISTORY', wc.id, cfg]; network.sendto(network.historyKeeper, JSON.stringify(msg)).then(cb, function (err) { throw new Error(err); }); }, function (err) { throw new Error(err); }); }; var channels = Msg.channels = window.channels = {}; var pushMsg = function (common, channel, cryptMsg) { var msg = channel.encryptor.decrypt(cryptMsg); var parsedMsg = JSON.parse(msg); console.log(parsedMsg); if (parsedMsg[0] === Types.message) { parsedMsg.shift(); channel.messages.push([cryptMsg.slice(0,64), parsedMsg]); return; } var proxy; if (parsedMsg[0] === Types.update) { proxy = common.getProxy(); if (parsedMsg[1] === common.getProxy().edPublic) { return; } var newdata = parsedMsg[3]; var data = getFriend(common, parsedMsg[1]); var types = []; Object.keys(newdata).forEach(function (k) { if (data[k] !== newdata[k]) { types.push(k); data[k] = newdata[k]; } }); channel.updateUI(types); return; } if (parsedMsg[0] === Types.unfriend) { proxy = common.getProxy(); if (parsedMsg[1] === common.getProxy().edPublic) { return; } channel.wc.leave(Types.unfriend); channel.removeUI(); return; } }; var onDirectMessage = function (common, msg, sender) { if (sender !== Msg.hk) { return; } var parsed = JSON.parse(msg); if ((parsed.validateKey || parsed.owners) && parsed.channel) { return; } if (parsed.state && parsed.state === 1 && parsed.channel) { if (channels[parsed.channel]) { // parsed.channel is Ready // TODO: call a function that shows that the channel is ready? (remove a spinner, ...) // channel[parsed.channel].ready(); channels[parsed.channel].ready = true; var updateTypes = channels[parsed.channel].updateOnReady; if (updateTypes) { channels[parsed.channel].updateUI(updateTypes); } } return; } var chan = parsed[3]; if (!chan || !channels[chan]) { return; } pushMsg(common, channels[chan], parsed[4]); }; var onMessage = function (common, msg, sender, chan) { if (!channels[chan.id]) { return; } pushMsg(common, channels[chan.id], msg); channels[chan.id].notify(); channels[chan.id].refresh(); }; var createChatBox = function (common, $container, edPublic) { var data = getFriend(common, edPublic); var proxy = common.getProxy(); var $header = $('
', {'class': 'header avatar'}).appendTo($container); $('
', {'class': 'messages'}).appendTo($container); var $inputBlock = $('
', {'class': 'input'}).appendTo($container); // Input var channel = channels[data.channel]; var $input = $('', {type: 'text'}).appendTo($inputBlock); var send = function () { if (!$input.val()) { return; } // Send the message var msg = [Types.message, proxy.edPublic, +new Date(), $input.val()]; var msgStr = JSON.stringify(msg); var cryptMsg = channel.encryptor.encrypt(msgStr); channel.wc.bcast(cryptMsg).then(function () { $input.val(''); pushMsg(common, channel, cryptMsg); channel.refresh(); }, function (err) { console.error(err); }); }; $('