define([ 'jquery', '/bower_components/chainpad-crypto/crypto.js', '/common/curve.js', '/common/common-hash.js', '/bower_components/marked/marked.min.js', '/common/common-realtime.js', // displayAvatar // whenRealtimeSyncs // getRealtime -> removeFromFriendList /* UI Messages confirm fixHTML displayAvatar clearOwnedChannel alert pushMsg removeFromFriendList onDirectMessage getNetwork getProxy pushMsg Init getNetwork getProxy onDirectMessage removeFromFriendList notify onMessage */ ], function ($, Crypto, Curve, Hash, Marked, Realtime) { var Msg = { inputs: [], }; var Types = { message: 'MSG', update: 'UPDATE', unfriend: 'UNFRIEND', mapId: 'MAP_ID', mapIdAck: 'MAP_ID_ACK' }; // TODO // - mute a channel (hide notifications or don't open it?) var ready = []; var pending = {}; var pendingRequests = []; var parseMessage = function (content) { return Marked(content); }; var createData = Msg.createData = function (proxy, hash) { return { channel: hash || Hash.createChannelId(), displayName: proxy['cryptpad.username'], profile: proxy.profile && proxy.profile.view, edPublic: proxy.edPublic, curvePublic: proxy.curvePublic, avatar: proxy.profile && proxy.profile.avatar }; }; var getFriend = function (proxy, pubkey) { if (pubkey === proxy.curvePublic) { var data = createData(proxy); delete data.channel; return data; } return proxy.friends ? proxy.friends[pubkey] : undefined; }; var removeFromFriendList = function (proxy, realtime, curvePublic, cb) { if (!proxy.friends) { return; } var friends = proxy.friends; delete friends[curvePublic]; Realtime.whenRealtimeSyncs(realtime, cb); }; var getFriendList = Msg.getFriendList = function (proxy) { if (!proxy.friends) { proxy.friends = {}; } return proxy.friends; }; var eachFriend = function (friends, cb) { Object.keys(friends).forEach(function (id) { if (id === 'me') { return; } cb(friends[id], id, friends); }); }; Msg.getFriendChannelsList = function (proxy) { var list = []; eachFriend(proxy, function (friend) { list.push(friend.channel); }); return list; }; // Messaging tools var avatars = {}; // TODO make this internal to the messenger var channels = Msg.channels = window.channels = {}; var UI = Msg.UI = {}; UI.init = function (common, $listContainer, $msgContainer) { var ui = { containers: { friendList: $listContainer, messages: $msgContainer, }, }; ui.addToFriendList = function (data, display, remove) { var $block = ui.containers.friendBlock; var $friend = $('
', {'class': 'friend avatar'}).appendTo($block); $friend.data('key', data.curvePublic); var $rightCol = $('', {'class': 'right-col'}); $('', {'class': 'name'}).text(data.displayName).appendTo($rightCol); var $remove = $('', {'class': 'remove fa fa-user-times'}).appendTo($rightCol); $remove.attr('title', common.Messages.contacts_remove); $friend.dblclick(function () { if (data.profile) { window.open('/profile/#' + data.profile); } }); $friend.click(function () { display(data.curvePublic); }); $remove.click(function (e) { e.stopPropagation(); common.confirm(common.Messages._getKey('contacts_confirmRemove', [ common.fixHTML(data.displayName) ]), function (yes) { if (!yes) { return; } remove(data.curvePublic); }, null, true); }); 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); }); } $('', {'class': 'status'}).appendTo($friend); }; ui.createFriendList = function (friends, display, remove) { var $block = ui.containers.friendBlock = $('
'); eachFriend(friends, function (friend) { ui.addToFriendList(friend, display, remove); }); $block.appendTo($listContainer); }; ui.notify = function (curvePublic) { var $friend = $listContainer.find('.friend').filter(function (idx, el) { return $(el).data('key') === curvePublic; }); $friend.addClass('notify'); }; ui.unnotify = function (curvePublic) { var $friend = $listContainer.find('.friend').filter(function (idx, el) { return $(el).data('key') === curvePublic; }); $friend.removeClass('notify'); }; ui.update = function (curvePublic, types) { var proxy = common.getProxy(); var data = getFriend(proxy, curvePublic); var chan = channels[data.channel]; if (!chan.ready) { chan.updateOnReady = (chan.updateOnReady || []).concat(types); return; } var $friend = $listContainer.find('.friend').filter(function (idx, el) { return $(el).data('key') === curvePublic; }); if (types.indexOf('displayName') >= 0) { $friend.find('.name').text(data.displayName); } if (types.indexOf('avatar') >= 0) { $friend.find('.default').remove(); $friend.find('media-tag').remove(); if (data.avatar && avatars[data.avatar]) { $friend.prepend(avatars[data.avatar]); } else { common.displayAvatar($friend, data.avatar, data.displayName, function ($img) { if (data.avatar && $img) { avatars[data.avatar] = $img[0].outerHTML; } }); } } }; ui.updateStatus = function (curvePublic, online) { ui.getFriend(curvePublic).find('.status') .attr('class', 'status ' + (online? 'online' : 'offline')); }; ui.getChannel = function (curvePublic) { var $chat = $msgContainer.find('.chat').filter(function (idx, el) { return $(el).data('key') === curvePublic; }); return $chat.length? $chat: null; }; ui.hideInfo = function () { $msgContainer.find('.info').hide(); }; ui.showInfo = function () { $msgContainer.find('.info').show(); }; ui.createChat = function (curvePublic) { return $('
', {'class':'chat'}) .data('key', curvePublic).appendTo($msgContainer); }; ui.hideChat = function () { $msgContainer.find('.chat').hide(); }; ui.getFriend = function (curvePublic) { return $listContainer.find('.friend').filter(function (idx, el) { return $(el).data('key') === curvePublic; }); }; ui.remove = function (curvePublic) { var $friend = ui.getFriend(curvePublic); var $chat = ui.getChannel(curvePublic); $friend.remove(); if ($chat) { $chat.remove(); } ui.showInfo(); }; ui.createMessage = function (msg, name) { var $msg = $('
', {'class': 'message'}) .attr('title', msg.time ? new Date(msg.time).toLocaleString(): '?'); if (name) { $('
', {'class':'sender'}).text(name).appendTo($msg); } $('
', {'class':'content'}).html(parseMessage(msg.text)).appendTo($msg); return $msg; }; ui.setEditable = function (bool) { bool = !bool; var input = ui.input; if (!input) { return; } if (bool) { input.setAttribute('disabled', bool); } else { input.removeAttribute('disabled'); } if (common.Messages) { // set placeholder var placeholder = bool? common.Messages.disconnected: common.Messages.contacts_typeHere; input.setAttribute('placeholder', placeholder); } }; ui.createChatBox = function (proxy, $container, curvePublic) { var data = getFriend(proxy, curvePublic); // Input var channel = channels[data.channel]; var $header = $('
', { 'class': 'header', }).appendTo($container); var $avatar = $('
', {'class': 'avatar'}).appendTo($header); // more history... $('', { 'class': 'more-history', }) .text('get more history') .click(function () { console.log("GETTING HISTORY"); channel.getPreviousMessages(); }) .appendTo($header); var $removeHistory = $('', { 'class': 'remove-history fa fa-eraser', title: common.Messages.contacts_removeHistoryTitle }) .click(function () { common.confirm(common.Messages.contacts_confirmRemoveHistory, function (yes) { if (!yes) { return; } common.clearOwnedChannel(data.channel, function (e) { if (e) { console.error(e); common.alert(common.Messages.contacts_removeHistoryServerError); return; } }); }); }); $removeHistory.appendTo($header); $('
', {'class': 'messages'}).appendTo($container); var $inputBlock = $('
', {'class': 'input'}).appendTo($container); var $input = $('