Merge remote-tracking branch 'origin/communities-comments' into communities-comments

pull/1/head
David Benqué 5 years ago
commit 6274591fab

@ -7,12 +7,18 @@
.comments_main() { .comments_main() {
@data-color: #888; @data-color: #888;
overflow-y: auto; overflow-y: auto;
color: @cryptpad_text_col;
.buttons_main(); .buttons_main();
.cp-comment-reply { .cp-comment-reply {
margin-left: 30px; margin-left: 30px;
} }
.cp-comment-deleted {
background: white;
font-size: 14px;
padding: 5px;
}
.cp-comment-form { .cp-comment-form {
@ -72,6 +78,7 @@
align-items: center; align-items: center;
display: flex; display: flex;
background-color: white; background-color: white;
position: relative;
padding: 5px; padding: 5px;
box-sizing: content-box; box-sizing: content-box;
.avatar_main(40px); .avatar_main(40px);
@ -85,6 +92,18 @@
color: @data-color; color: @data-color;
} }
} }
.cp-comment-edit {
position: absolute;
right: 0;
top: 0;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
&:hover {
color: lighten(@cryptpad_text_col, 10%);
}
}
} }
.cp-comment-content { .cp-comment-content {
background-color: white; background-color: white;
@ -92,6 +111,12 @@
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-word; word-break: break-word;
} }
.cp-comment-edited {
background-color: white;
font-size: 13px;
color: @data-color;
padding: 0 5px;
}
.cp-comment-actions { .cp-comment-actions {
display: none; display: none;
text-align: right; text-align: right;

@ -3870,7 +3870,7 @@ define([
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
} catch (err) { console.error(err); } } catch (err) { console.error(err, $t); }
} }
}).autocomplete({ }).autocomplete({
minLength: 0, minLength: 0,

@ -25,9 +25,11 @@ define([
u: id, u: id,
m: "str", // comment m: "str", // comment
t: +new Date, t: +new Date,
v: "str" // value of the commented content v: "str", // value of the commented content
e: undefined/1, // edited
d: undefined/1, // deleted
}], }],
(deleted: undefined/true,) d: undefined/1,
} }
} }
} }
@ -130,11 +132,10 @@ define([
}; };
var cleanMentions = function ($el, full) { var cleanMentions = function ($el) {
$el.html(''); $el.html('');
var el = $el[0]; var el = $el[0];
var allowed = full ? ['data-profile', 'data-name', 'data-avatar', 'class'] var allowed = ['data-profile', 'data-name', 'data-avatar', 'class'];
: ['class'];
// Remove unnecessary/unsafe attributes // Remove unnecessary/unsafe attributes
for (var i=el.attributes.length-1; i>0; i--) { for (var i=el.attributes.length-1; i>0; i--) {
var name = el.attributes[i] && el.attributes[i].name; var name = el.attributes[i] && el.attributes[i].name;
@ -144,10 +145,12 @@ define([
} }
}; };
Messages.comments_deleted = "Comment deleted by its author"; // XXX
Messages.comments_edited = "Edited"; // XXX
Messages.comments_submit = "Submit"; // XXX Messages.comments_submit = "Submit"; // XXX
Messages.comments_reply = "Reply"; // XXX Messages.comments_reply = "Reply"; // XXX
Messages.comments_resolve = "Resolve"; // XXX Messages.comments_resolve = "Resolve"; // XXX
var getCommentForm = function (Env, reply, _cb) { var getCommentForm = function (Env, reply, _cb, editContent) {
var cb = Util.once(_cb); var cb = Util.once(_cb);
var userData = Env.metadataMgr.getUserData(); var userData = Env.metadataMgr.getUserData();
var name = Util.fixHTML(userData.name || Messages.anonymous); var name = Util.fixHTML(userData.name || Messages.anonymous);
@ -189,6 +192,7 @@ define([
if (!curve || !notif) { return; } if (!curve || !notif) { return; }
notify[curve] = notif; notify[curve] = notif;
}); });
$clone.find('br').replaceWith("\n");
$clone.find('> *:not(.cp-mentions)').remove(); $clone.find('> *:not(.cp-mentions)').remove();
var content = clone.innerHTML.trim(); var content = clone.innerHTML.trim();
if (!content) { return; } if (!content) { return; }
@ -218,6 +222,7 @@ define([
e.stopPropagation(); e.stopPropagation();
if (e.which === 27) { if (e.which === 27) {
$(cancel).click(); $(cancel).click();
e.stopImmediatePropagation();
} }
if (e.which === 13 && !e.shiftKey) { if (e.which === 13 && !e.shiftKey) {
// Submit form on Enter is the autocompelte menu is not visible // Submit form on Enter is the autocompelte menu is not visible
@ -226,6 +231,7 @@ define([
if (visible) { return; } if (visible) { return; }
} catch (err) {} } catch (err) {}
$(submit).click(); $(submit).click();
e.stopImmediatePropagation();
e.preventDefault(); e.preventDefault();
} }
}).click(function (e) { }).click(function (e) {
@ -247,6 +253,22 @@ define([
}); });
} }
var deleteButton;
// Edit? start with the old content
// Add a space to make sure we won't end with a mention and a bad cursor
if (editContent) {
textarea.innerHTML = editContent + " ";
deleteButton = h('button.btn.btn-danger', {
tabindex: 1
}, [
h('i.fa.fa-times'),
Messages.kanban_delete
]);
$(deleteButton).click(function (e) {
e.stopPropagation();
cb();
});
}
setTimeout(function () { setTimeout(function () {
@ -262,6 +284,7 @@ define([
]), ]),
h('div.cp-comment-form-actions', [ h('div.cp-comment-form-actions', [
cancel, cancel,
deleteButton,
submit submit
]) ])
]); ]);
@ -270,43 +293,60 @@ define([
var redrawComments = function (Env) { var redrawComments = function (Env) {
// Don't redraw if there were no change // Don't redraw if there were no change
var str = Sortify(Env.comments || {}); var str = Sortify(Env.comments || {});
if (str === Env.oldComments) { return; } if (str === Env.oldComments) { return; }
Env.oldComments = str; Env.oldComments = str;
// Store existing input form in memory
var $oldInput = Env.$container.find('.cp-comment-form').detach(); var $oldInput = Env.$container.find('.cp-comment-form').detach();
if ($oldInput.length !== 1) { $oldInput = undefined; } if ($oldInput.length !== 1) { $oldInput = undefined; }
// Remove everything
Env.$container.html(''); Env.$container.html('');
// "show" tells us if we need to display the "comments" column or not
var show = false;
// Add invisible label for accessibility tools
var label = h('label#cp-comments-label', Messages.comments_comment); var label = h('label#cp-comments-label', Messages.comments_comment);
Env.$container.append(label); Env.$container.append(label);
var show = false; // If we were adding a new comment, redraw our form
if ($oldInput && !$oldInput.attr('data-uid')) { if ($oldInput && !$oldInput.attr('data-uid')) {
show = true; show = true;
Env.$container.append($oldInput); Env.$container.append($oldInput);
} }
var order = Env.$inner.find('comment').map(function (i, el) { var userData = Env.metadataMgr.getUserData();
// Get all the comment threads in their order in the pad
var threads = Env.$inner.find('comment').map(function (i, el) {
return el.getAttribute('data-uid'); return el.getAttribute('data-uid');
}).toArray(); }).toArray();
var done = [];
order.forEach(function (key) {
// Avoir duplicates
if (done.indexOf(key) !== -1) { return; }
done.push(key);
// Draw all comment threads
Util.deduplicateString(threads).forEach(function (key) {
// Get thread data
var obj = Env.comments.data[key]; var obj = Env.comments.data[key];
if (!obj || obj.deleted || !Array.isArray(obj.m) || !obj.m.length) { if (!obj || obj.d || !Array.isArray(obj.m) || !obj.m.length) {
return; return;
} }
// If at least one thread is visible, display the "comments" column
show = true; show = true;
var content = []; var content = [];
obj.m.forEach(function (msg, i) { var $div;
var $actions;
// Draw all messages for this thread
(obj.m || []).forEach(function (msg, i) {
var replyCls = i === 0 ? '' : '.cp-comment-reply';
if (msg.d) {
content.push(h('div.cp-comment.cp-comment-deleted'+replyCls,
Messages.comments_deleted));
return;
}
var author = typeof(msg.u) === "number" ? var author = typeof(msg.u) === "number" ?
((Env.comments.authors || {})[msg.u] || {}) : ((Env.comments.authors || {})[msg.u] || {}) :
{ name: msg.u }; { name: msg.u };
@ -354,16 +394,71 @@ define([
} }
}); });
// edited state
var edited;
if (msg.e) {
edited = h('div.cp-comment-edited', Messages.comments_edited);
}
var container;
// Add edit button when applicable (last message of the thread, written by ourselves)
var edit;
if (i === (obj.m.length -1) && author.curvePublic === userData.curvePublic) {
edit = h('span.cp-comment-edit', {
title: Messages.clickToEdit
}, h('i.fa.fa-pencil'));
$(edit).click(function (e) {
e.stopPropagation();
Env.$container.find('.cp-comment-form').remove();
if ($actions) { $actions.hide(); }
var form = getCommentForm(Env, key, function (val) {
// Show the "reply" and "resolve" buttons again
$(form).closest('.cp-comment-container')
.find('.cp-comment-actions').css('display', '');
$(form).remove();
var obj = Env.comments.data[key];
if (!obj || !Array.isArray(obj.m)) { return; }
var msg = obj.m[i];
if (!msg) { return; }
// i is our index
if (!val) {
msg.d = 1;
if (container) {
$(container).addClass('cp-comment-deleted')
.html(Messages.comments_deleted);
}
if (obj.m.length === 1) {
delete Env.comments.data[key];
}
} else {
msg.e = 1;
msg.m = val;
}
// Send to chainpad
updateMetadata(Env);
Env.framework.localChange();
}, m.innerHTML);
if (!$div) { return; }
$div.append(form);
});
}
// Add the comment // Add the comment
content.push(h('div.cp-comment'+(i === 0 ? '' : '.cp-comment-reply'), [ content.push(container = h('div.cp-comment'+replyCls, [
h('div.cp-comment-header', [ h('div.cp-comment-header', [
avatar, avatar,
h('span.cp-comment-metadata', [ h('span.cp-comment-metadata', [
h('span.cp-comment-author', name), h('span.cp-comment-author', name),
h('span.cp-comment-time', date.toLocaleString()) h('span.cp-comment-time', date.toLocaleString())
])
]), ]),
m edit
]),
m,
edited
])); ]));
}); });
@ -386,19 +481,20 @@ define([
reply, reply,
resolve resolve
])); ]));
var $actions = $(actions); $actions = $(actions);
var div; var div;
Env.$container.append(div = h('div.cp-comment-container', { Env.$container.append(div = h('div.cp-comment-container', {
'data-uid': key, 'data-uid': key,
tabindex: 1 tabindex: 1
}, content)); }, content));
var $div = $(div); $div = $(div);
$(reply).click(function (e) { $(reply).click(function (e) {
e.stopPropagation(); e.stopPropagation();
$actions.hide(); $actions.hide();
var form = getCommentForm(Env, key, function (val) { var form = getCommentForm(Env, key, function (val) {
// Show the "reply" and "resolve" buttons again
$(form).closest('.cp-comment-container') $(form).closest('.cp-comment-container')
.find('.cp-comment-actions').css('display', ''); .find('.cp-comment-actions').css('display', '');
$(form).remove(); $(form).remove();
@ -434,7 +530,11 @@ define([
// Make sure the submit button is visible: scroll by the height of the form // Make sure the submit button is visible: scroll by the height of the form
setTimeout(function () { setTimeout(function () {
var yContainer = Env.$container[0].getBoundingClientRect().bottom;
var yActions = form.getBoundingClientRect().bottom;
if (yActions > yContainer) {
Env.$container.scrollTop(Env.$container.scrollTop() + 55); Env.$container.scrollTop(Env.$container.scrollTop() + 55);
}
}); });
}); });
@ -531,7 +631,7 @@ define([
// If there is no comment stored in the metadata, abort // If there is no comment stored in the metadata, abort
var comments = Object.keys(Env.comments.data || {}).filter(function (id) { var comments = Object.keys(Env.comments.data || {}).filter(function (id) {
return !Env.comments.data[id].deleted; return !Env.comments.data[id].d;
}); });
var changed = false; var changed = false;
@ -556,8 +656,8 @@ define([
} }
// If this comment was deleted, we're probably using "undo" to restore it: // If this comment was deleted, we're probably using "undo" to restore it:
// remove the "deleted" state and continue // remove the "deleted" state and continue
if (obj.deleted) { if (obj.d) {
delete obj.deleted; delete obj.d;
changed = true; changed = true;
} }
return id; return id;
@ -575,7 +675,7 @@ define([
// comment has been deleted // comment has been deleted
var data = Env.comments.data[uid]; var data = Env.comments.data[uid];
if (!data) { return; } if (!data) { return; }
data.deleted = true; data.d = 1;
//delete Env.comments.data[uid]; //delete Env.comments.data[uid];
changed = true; changed = true;
}); });
@ -711,7 +811,7 @@ define([
// Clear data // Clear data
var data = (Env.comments && Env.comments.data) || {}; var data = (Env.comments && Env.comments.data) || {};
Object.keys(data).forEach(function (uid) { Object.keys(data).forEach(function (uid) {
if (data[uid].deleted) { delete data[uid]; } if (data[uid].d) { delete data[uid]; }
}); });
// Commit // Commit

Loading…
Cancel
Save