Avatar upload in the profile app

This commit is contained in:
yflory 2017-06-28 16:59:35 +02:00
parent 6c94605b9b
commit 19ff8a345d
4 changed files with 196 additions and 38 deletions

View File

@ -12,12 +12,13 @@ define([
'/common/common-metadata.js', '/common/common-metadata.js',
'/common/common-codemirror.js', '/common/common-codemirror.js',
'/common/common-file.js', '/common/common-file.js',
'/file/file-crypto.js',
'/common/clipboard.js', '/common/clipboard.js',
'/common/pinpad.js', '/common/pinpad.js',
'/customize/application_config.js' '/customize/application_config.js'
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata, ], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata,
CodeMirror, Files, Clipboard, Pinpad, AppConfig) { CodeMirror, Files, FileCrypto, Clipboard, Pinpad, AppConfig) {
/* This file exposes functionality which is specific to Cryptpad, but not to /* This file exposes functionality which is specific to Cryptpad, but not to
any particular pad type. This includes functions for committing metadata any particular pad type. This includes functions for committing metadata
@ -974,9 +975,14 @@ define([
var ev = { var ev = {
target: data.target target: data.target
}; };
if (data.filter && !data.filter(file)) {
common.log('TODO: invalid avatar (type or size)');
return;
}
data.FM.handleFile(file, ev); data.FM.handleFile(file, ev);
if (callback) { callback(); } if (callback) { callback(); }
}); });
if (data.accept) { $input.attr('accept', data.accept); }
button.click(function () { $input.click(); }); button.click(function () { $input.click(); });
break; break;
case 'template': case 'template':
@ -1129,6 +1135,70 @@ define([
return button; return button;
}; };
common.avatarAllowedTypes = [
'image/png',
'image/jpeg',
'image/jpg',
'image/gif',
];
common.displayAvatar = function ($container, href) {
var MutationObserver = window.MutationObserver;
$container.html('');
if (href) {
var parsed = common.parsePadUrl(href);
var secret = common.getSecrets('file', parsed.hash);
if (secret.keys && secret.channel) {
var cryptKey = secret.keys && secret.keys.fileKeyStr;
var hexFileName = common.base64ToHex(secret.channel);
var src = common.getBlobPathFromHex(hexFileName);
common.getFileSize(href, function (e, data) {
if (e) { return void console.error(e); }
if (typeof data !== "number") { return; }
if (common.bytesToMegabytes(data) > 0.5) { return; }
var $img = $('<media-tag>').appendTo($container);
$img.attr('src', src);
$img.attr('data-crypto-key', 'cryptpad:' + cryptKey);
require(['/common/media-tag.js'], function (MediaTag) {
MediaTag.CryptoFilter.setAllowedMediaTypes(common.avatarAllowedTypes);
MediaTag($img[0]);
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList' && mutation.addedNodes.length) {
console.log(mutation);
if (mutation.addedNodes.length > 1 ||
mutation.addedNodes[0].nodeName !== 'IMG') {
$img.remove();
return;
//TODO display default avatar
}
var $image = $img.find('img');
var onLoad = function () {
var w = $image.width();
var h = $image.height();
if (w>h) {
$image.css('max-height', '100%');
$img.css('flex-direction', 'row');
return;
}
$image.css('max-width', '100%');
$img.css('flex-direction', 'column');
};
if ($image[0].complete) { onLoad(); }
$image.on('load', onLoad);
}
});
});
observer.observe($img[0], {
attributes: false,
childList: true,
characterData: false
});
});
});
}
}
};
// Create a button with a dropdown menu // Create a button with a dropdown menu
// input is a config object with parameters: // input is a config object with parameters:
// - container (optional): the dropdown container (span) // - container (optional): the dropdown container (span)

View File

@ -156,7 +156,6 @@ define([
MediaTag(el); MediaTag(el);
var observer = new MutationObserver(function(mutations) { var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) { mutations.forEach(function(mutation) {
console.log(mutation);
if (mutation.type === 'childList') { if (mutation.type === 'childList') {
var list_values = [].slice.call(el.children); var list_values = [].slice.call(el.children);
mediaMap[el.getAttribute('src')] = list_values; mediaMap[el.getAttribute('src')] = list_values;

View File

@ -196,51 +196,105 @@ define([
cb(); cb();
}; };
var rt = APP.lm.realtime; var rt = APP.lm.realtime;
var placeholder = "URL"; //TODO var placeholder = "URL"; //XXX
createEditableInput($block, LINK_ID, placeholder, getValue, setValue, rt); createEditableInput($block, LINK_ID, placeholder, getValue, setValue, rt);
}; };
var addAvatar = function ($container) { var addAvatar = function ($container) {
var $block = $('<div>', {id: AVATAR_ID}).appendTo($container); var $block = $('<div>', {id: AVATAR_ID}).appendTo($container);
var $span = $('<span>').appendTo($block); var $span = $('<span>').appendTo($block);
if (APP.lm.proxy.avatar) { var allowedMediaTypes = Cryptpad.avatarAllowedTypes;
//var file = APP.lm.proxy.avatar; var displayAvatar = function () {
var $img = $('<media-tag>').appendTo($span); $span.html('');
$img.attr('src', '/blob/45/45170bcd64aae1726b0b0e06c4360181a08bad9596640863'); if (!APP.lm.proxy.avatar) {
$img.attr('data-crypto-key', 'cryptpad:5vs/ciPzSAyHeP6XRwxpFZt/cjkRC+EE2CRw+/xfcVI='); $('<img>', {
require(['/common/media-tag.js'], function (MediaTag) { src: '/customize/images/avatar.png',
var allowedMediaTypes = [ title: 'Avatar', // XXX
'image/png', alt: 'Avatar'
'image/jpeg', }).appendTo($span);
'image/jpg', return;
'image/gif', }
]; Cryptpad.displayAvatar($span, APP.lm.proxy.avatar);
MediaTag.CryptoFilter.setAllowedMediaTypes(allowedMediaTypes);
MediaTag($img[0]);
});
}
if (APP.readOnly) { return; }
//var $button = $('<button>', {'class': 'btn btn-success'}).text('TODO: change avatar'); if (APP.readOnly) { return; }
//$block.append($button);
var $delButton = $('<button>', {'class': 'delete btn btn-danger fa fa-times'}); //XXX
$span.append($delButton);
$delButton.click(function () {
console.log('clicked');
var oldChanId = Cryptpad.hrefToHexChannelId(APP.lm.proxy.avatar);
Cryptpad.unpinPads([oldChanId], function (e) {
if (e) { Cryptpad.log(e); }
console.log('unpinned');
delete APP.lm.proxy.avatar;
delete Cryptpad.getProxy().profile.avatar;
Cryptpad.whenRealtimeSyncs(APP.lm.realtime, function () {
console.log('synced1');
var driveRt = Cryptpad.getStore().getProxy().info.realtime;
Cryptpad.whenRealtimeSyncs(driveRt, function () {
console.log('synced2');
displayAvatar();
});
});
});
});
};
displayAvatar();
if (APP.readOnly) { return; }
var fmConfig = { var fmConfig = {
noHandlers: true, noHandlers: true,
noStore: true, noStore: true,
body: $('body'), body: $('body'),
onUploaded: function (ev, data) { onUploaded: function (ev, data) {
console.log(data); var chanId = Cryptpad.hrefToHexChannelId(data.url);
var profile = Cryptpad.getProxy().profile;
var old = profile.avatar;
var todo = function () {
Cryptpad.pinPads([chanId], function (e) {
if (e) { return void Cryptpad.log(e); }
APP.lm.proxy.avatar = data.url;
Cryptpad.getProxy().profile.avatar = data.url;
Cryptpad.whenRealtimeSyncs(APP.lm.realtime, function () {
var driveRt = Cryptpad.getStore().getProxy().info.realtime;
Cryptpad.whenRealtimeSyncs(driveRt, function () {
displayAvatar();
});
});
});
};
if (old) {
var oldChanId = Cryptpad.hrefToHexChannelId(old);
Cryptpad.unpinPads([oldChanId], function (e) {
if (e) { Cryptpad.log(e); }
todo();
});
return;
}
todo();
} }
}; };
APP.FM = Cryptpad.createFileManager(fmConfig); APP.FM = Cryptpad.createFileManager(fmConfig);
var data = {FM: APP.FM}; var data = {
$block.append(Cryptpad.createButton('upload', false, data)); FM: APP.FM,
filter: function (file) {
var sizeMB = Cryptpad.bytesToMegabytes(file.size);
var type = file.type;
return sizeMB <= 0.5 && allowedMediaTypes.indexOf(type) !== -1;
},
accept: ".gif,.jpg,.jpeg,.png"
};
var $upButton = Cryptpad.createButton('upload', false, data);
$upButton.text(" Upload a new avatar");
$upButton.prepend($('<span>', {'class': 'fa fa-upload'}));
$block.append($upButton);
}; };
var addDescription = function ($container) { var addDescription = function ($container) {
var $block = $('<div>', {id: DESCRIPTION_ID}).appendTo($container); var $block = $('<div>', {id: DESCRIPTION_ID}).appendTo($container);
if (APP.readOnly) { if (APP.readOnly) {
if (!APP.lm.proxy.description.trim()) { return void $block.hide(); }
var $div = $('<div>', {'class': 'rendered'}).appendTo($block); var $div = $('<div>', {'class': 'rendered'}).appendTo($block);
var val = Marked(APP.lm.proxy.description); var val = Marked(APP.lm.proxy.description);
$div.html(val); $div.html(val);
@ -274,13 +328,10 @@ define([
var addPublicKey = function ($container) { var addPublicKey = function ($container) {
var $block = $('<div>', {id: PUBKEY_ID}); var $block = $('<div>', {id: PUBKEY_ID});
var pubKey = Cryptpad.getProxy().edPublic;
$block.text(pubKey);
$container.append($block); $container.append($block);
}; };
var onReady = function () { var onReady = function () {
// TODO: on reconnect, this is called multiple times...
APP.$container.find('#'+CREATE_ID).remove(); APP.$container.find('#'+CREATE_ID).remove();
if (!APP.initialized) { if (!APP.initialized) {
@ -332,13 +383,32 @@ define([
var secret = Cryptpad.getSecrets(); var secret = Cryptpad.getSecrets();
obj.profile = {}; obj.profile = {};
var channel = Cryptpad.createChannelId(); var channel = Cryptpad.createChannelId();
obj.profile.edit = Cryptpad.getEditHashFromKeys(channel, secret.keys); Cryptpad.pinPads([channel], function (e) {
obj.profile.view = Cryptpad.getViewHashFromKeys(channel, secret.keys); if (e) {
obj.profile.name = APP.rt.proxy[Cryptpad.displayNameKey] || ''; if (e === 'E_OVER_LIMIT') {
andThen(obj.profile.edit); Cryptpad.alert(Messages.pinLimitNotPinned, null, true);
}
return void Cryptpad.log('Error while creating your profile: ' + e); // XXX
}
obj.profile.edit = Cryptpad.getEditHashFromKeys(channel, secret.keys);
obj.profile.view = Cryptpad.getViewHashFromKeys(channel, secret.keys);
obj.profile.name = APP.rt.proxy[Cryptpad.displayNameKey] || '';
andThen(obj.profile.edit);
});
}; };
// TODO: if not logged in, display a register button here? if (!Cryptpad.isLoggedIn()) { // XXX
var $p = $('<p>').text('TODO: You have to register to create a profile');
var $a = $('<a>', {
href: '/register/'
});
$('<button>', {
'class': 'btn btn-success',
}).text(Messages.login_register).appendTo($a);
$p.append($('<br>')).append($a);
APP.$container.append($p);
return;
}
var $create = $('<div>', {id: CREATE_ID}); var $create = $('<div>', {id: CREATE_ID});
var $button = $('<button>', {'class': 'btn btn-success'}); var $button = $('<button>', {'class': 'btn btn-success'});
$button.text('TODO: create a profile?').click(todo).appendTo($create); // XXX $button.text('TODO: create a profile?').click(todo).appendTo($create); // XXX

View File

@ -23,25 +23,43 @@
width: 300px; width: 300px;
//height: 350px; //height: 350px;
margin: 10px; margin: 10px;
margin-right: 20px;
text-align: center; text-align: center;
&> span { &> span {
display: inline-block; display: inline-block;
line-height: 300px;
text-align: center; text-align: center;
height: 300px; height: 300px;
width: 300px;
border: 1px solid black; border: 1px solid black;
border-radius: 10px; border-radius: 10px;
overflow: hidden; overflow: hidden;
position: relative;
.delete {
right: 0;
position: absolute;
opacity: 0.7;
&:hover {
opacity: 1;
}
}
} }
img { img {
max-width: 300px; max-width: 100%;
max-height: 300px; max-height: 100%;
vertical-align: top;
} }
media-tag { media-tag {
height: 100%; height: 100%;
display: inline-block; width: 100%;
display: inline-flex;
justify-content: center;
align-items: center;
img { img {
vertical-align: top; min-width: 100%;
min-height: 100%;
max-width: none;
max-height: none;
flex-shrink: 0;
} }
} }
button { button {
@ -83,6 +101,7 @@
position: relative; position: relative;
font-size: 16px; font-size: 16px;
border: 1px solid #DDD; border: 1px solid #DDD;
margin-bottom: 20px;
.rendered { .rendered {
padding: 0 15px; padding: 0 15px;
} }