', {'class':'sender'}).text(name).appendTo($msg);
+ }
+ channel.lastSender = msg[0];
+
+ // content
+ $('
', {'class':'content'}).text(msg[2]).appendTo($msg);
+ }
+ $messages.scrollTop($messages[0].scrollHeight);
+ channel.lastDisplayed = i-1;
+ channel.unnotify();
+
+ if (messages.length > 10) {
+ var lastKnownMsg = messages[messages.length - 11];
+ data.lastKnownHash = lastKnownMsg[0];
+ }
+ };
+ // Display a new channel
+ var display = function (edPublic) {
+ var isNew = false;
+ var $chat = $msgContainer.find('.chat').filter(function (idx, el) {
+ return $(el).data('key') === edPublic;
+ });
+ if (!$chat.length) {
+ $chat = $('
', {'class':'chat'}).data('key', edPublic).appendTo($msgContainer);
+ createChatBox(common, $chat, edPublic);
+ isNew = true;
+ }
+ // Show the correct div
+ $msgContainer.find('.chat').hide();
+ $chat.show();
+
+ Msg.active = edPublic;
+
+ refresh(edPublic);
+ };
+
+ // Display friend list
+ common.getFriendListUI(common, display).appendTo($listContainer);
+
+ // Notify on new messages
+ var notify = function (edPublic) {
+ if (Msg.active === edPublic) { return; }
+ var $friend = $listContainer.find('.friend').filter(function (idx, el) {
+ return $(el).data('key') === edPublic;
+ });
+ $friend.addClass('notify');
+ };
+ var unnotify = function (edPublic) {
+ var $friend = $listContainer.find('.friend').filter(function (idx, el) {
+ return $(el).data('key') === edPublic;
+ });
+ $friend.removeClass('notify');
+ };
+
+ // Open the channels
+ Object.keys(friends).forEach(function (f) {
+ var data = friends[f];
+ var keys = Curve.deriveKeys(data.curvePublic, proxy.curvePrivate);
+ var encryptor = Curve.createEncryptor(keys);
+ channels[data.channel] = {
+ keys: keys,
+ encryptor: encryptor,
+ messages: [],
+ refresh: function () { refresh(data.edPublic); },
+ notify: function () { notify(data.edPublic); },
+ unnotify: function () { unnotify(data.edPublic); }
+ };
+ network.join(data.channel).then(function (chan) {
+ channels[data.channel].wc = chan;
+ chan.on('message', function (msg, sender) {
+ onMessage(msg, sender, chan);
+ });
+ var cfg = {
+ validateKey: keys.validateKey,
+ owners: [proxy.edPublic, data.edPublic],
+ lastKnownHash: data.lastKnownHash
+ };
+ var msg = ['GET_HISTORY', chan.id, cfg];
+ network.sendto(network.historyKeeper, JSON.stringify(msg))
+ .then($.noop, function (err) {
+ throw new Error(err);
+ });
+ }, function (err) {
+ console.error(err);
+ });
+ });
+ };
+
+ // Invitation
+
// Remove should be called from the friend app at the moment
// The other user will know it from the private channel ("REMOVE_FRIEND" message?)
Msg.removeFromFriendList = function (common, edPublic, cb) {
@@ -87,23 +336,6 @@ define([
common.changeDisplayName(proxy[common.displayNameKey]);
};
- var createData = Msg.createData = function (common, hash) {
- var proxy = common.getProxy();
- return {
- channel: hash || common.createChannelId(),
- displayName: proxy[common.displayNameKey],
- profile: proxy.profile.view,
- edPublic: proxy.edPublic,
- curvePublic: proxy.curvePublic,
- avatar: proxy.profile.avatar
- };
- };
-
- var getFriend = function (common, pubkey) {
- var proxy = common.getProxy();
- return proxy.friends ? proxy.friends[pubkey] : undefined;
- };
-
Msg.addDirectMessageHandler = function (common) {
var network = common.getNetwork();
if (!network) { return void console.error('Network not ready'); }
@@ -183,7 +415,7 @@ define([
Msg.inviteFromUserlist = function (common, netfluxId) {
var network = common.getNetwork();
var parsed = common.parsePadUrl(window.location.href);
- if (!parsed.hashData) { return; } // TODO
+ if (!parsed.hashData) { return; }
// Message
var chan = parsed.hashData.channel;
var myData = createData(common);
diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js
index 1b3c346bd..2ce204a9d 100644
--- a/www/common/cryptpad-common.js
+++ b/www/common/cryptpad-common.js
@@ -111,6 +111,7 @@ define([
common.createInviteUrl = Hash.createInviteUrl;
// Messaging
+ common.initMessaging = Messaging.init;
common.addDirectMessageHandler = Messaging.addDirectMessageHandler;
common.inviteFromUserlist = Messaging.inviteFromUserlist;
common.createOwnedChannel = Messaging.createOwnedChannel;
@@ -176,6 +177,12 @@ define([
return store.getProfile().avatar;
}
};
+ common.getDisplayName = function () {
+ if (getProxy()) {
+ return getProxy()[common.displayNameKey] || '';
+ }
+ return '';
+ };
var feedback = common.feedback = function (action, force) {
if (force !== true) {
@@ -1325,7 +1332,6 @@ define([
img.onload = function () {
var w = img.width;
var h = img.height;
- console.log(w,h);
if (w>h) {
$image.css('max-height', '100%');
$img.css('flex-direction', 'column');
diff --git a/www/friends/main.js b/www/friends/main.js
index 80b037a27..adbc9a8d4 100644
--- a/www/friends/main.js
+++ b/www/friends/main.js
@@ -7,9 +7,9 @@ define([
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
'less!/customize/src/less/cryptpad.less',
], function ($, Crypto, Toolbar, Cryptpad) {
- var Messages = Cryptpad.Messages;
+ //var Messages = Cryptpad.Messages;
- var APP = {
+ var APP = window.APP = {
Cryptpad: Cryptpad
};
@@ -20,7 +20,7 @@ define([
var ifrw = $('#pad-iframe')[0].contentWindow;
var $iframe = $('#pad-iframe').contents();
- var $appContainer = $iframe.find('#app');
+ //var $appContainer = $iframe.find('#app');
var $list = $iframe.find('#friendList');
var $messages = $iframe.find('#messaging');
var $bar = $iframe.find('.toolbar-container');
@@ -37,7 +37,7 @@ define([
var toolbar = APP.toolbar = Toolbar.create(configTb);
toolbar.$rightside.html(''); // Remove the drawer if we don't use it to hide the toolbar
- Cryptpad.getFriendListUI(Cryptpad).appendTo($list);
+ Cryptpad.initMessaging(Cryptpad, $list, $messages);
Cryptpad.removeLoadingScreen();
};
diff --git a/www/friends/main.less b/www/friends/main.less
index b6dbaf9dc..c9b2ae06f 100644
--- a/www/friends/main.less
+++ b/www/friends/main.less
@@ -3,6 +3,7 @@
@button-border: 2px;
@bg-color: @toolbar-friends-bg;
+@color: @toolbar-friends-color;
html, body {
margin: 0px;
@@ -22,6 +23,7 @@ body {
display: flex;
justify-content: center;
align-items: center;
+ min-height: 0;
}
#app.ready {
@@ -34,14 +36,143 @@ body {
display: inline-block;
}
+
+@keyframes example {
+ 0% {
+ background: rgba(0,0,0,0.1);
+ }
+ 50% {
+ background: rgba(0,0,0,0.3);
+ }
+ 100% {
+ background: rgba(0,0,0,0.1);
+ }
+}
#friendList {
width: 350px;
height: 100%;
background-color: lighten(@bg-color, 10%);
+ .friend {
+ background: rgba(0,0,0,0.1);
+ padding: 5px;
+ margin: 10px;
+ cursor: pointer;
+ &:hover {
+ background-color: rgba(0,0,0,0.3);
+ }
+ &.notify {
+ animation: example 2s ease-in-out infinite;
+ }
+ }
+}
+
+#friendList .friend, #messaging .header {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-size: 16px;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ color: @color;
+ .default, media-tag {
+ display: inline-flex;
+ width: 50px;
+ height: 50px;
+ justify-content: center;
+ align-items: center;
+ margin-right: 5px;
+ border-radius: 10px / 6px;
+ overflow: hidden;
+ border: 1px solid black;
+ box-sizing: content-box;
+ }
+ .default {
+ .unselectable();
+ background: white;
+ color: black;
+ font-size: 40px;
+ }
+ .right-col {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ display: flex;
+ flex-flow: column;
+ .name {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ .friend {
+ padding: 0;
+ }
+ }
+ media-tag {
+ min-height: 50px;
+ min-width: 50px;
+ max-height: 50px;
+ max-width: 50px;
+ img {
+ color: #000;
+ min-width: 100%;
+ min-height: 100%;
+ max-width: none;
+ max-height: none; // To override 'media-tag img' in slide.less
+ }
+ }
+
+
}
#messaging {
flex: 1;
height: 100%;
background-color: lighten(@bg-color, 20%);
+ min-width: 0;
+ .header {
+ background-color: lighten(@bg-color, 15%);
+ padding: 10px;
+ }
+ .chat {
+ height: 100%;
+ display: flex;
+ flex-flow: column;
+ .messages {
+ padding: 0 20px;
+ margin: 10px 0;
+ flex: 1;
+ overflow-x: auto;
+ .message {
+ & > div {
+ padding: 0 10px;
+ }
+ .content {
+ overflow: hidden;
+ word-wrap: break-word;
+ }
+ .date {
+ display: none;
+ font-style: italic;
+ }
+ .sender {
+ margin-top: 10px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ .input {
+ background-color: lighten(@bg-color, 15%);
+ height: 50px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 75px;
+ input {
+ flex: 1;
+ }
+ }
}
+