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

This commit is contained in:
David Benqué 2020-04-29 15:58:52 +01:00
commit 6274591fab
3 changed files with 155 additions and 30 deletions

View file

@ -7,12 +7,18 @@
.comments_main() {
@data-color: #888;
overflow-y: auto;
color: @cryptpad_text_col;
.buttons_main();
.cp-comment-reply {
margin-left: 30px;
}
.cp-comment-deleted {
background: white;
font-size: 14px;
padding: 5px;
}
.cp-comment-form {
@ -72,6 +78,7 @@
align-items: center;
display: flex;
background-color: white;
position: relative;
padding: 5px;
box-sizing: content-box;
.avatar_main(40px);
@ -85,6 +92,18 @@
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 {
background-color: white;
@ -92,6 +111,12 @@
white-space: pre-wrap;
word-break: break-word;
}
.cp-comment-edited {
background-color: white;
font-size: 13px;
color: @data-color;
padding: 0 5px;
}
.cp-comment-actions {
display: none;
text-align: right;

View file

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

View file

@ -25,9 +25,11 @@ define([
u: id,
m: "str", // comment
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('');
var el = $el[0];
var allowed = full ? ['data-profile', 'data-name', 'data-avatar', 'class']
: ['class'];
var allowed = ['data-profile', 'data-name', 'data-avatar', 'class'];
// Remove unnecessary/unsafe attributes
for (var i=el.attributes.length-1; i>0; i--) {
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_reply = "Reply"; // 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 userData = Env.metadataMgr.getUserData();
var name = Util.fixHTML(userData.name || Messages.anonymous);
@ -189,6 +192,7 @@ define([
if (!curve || !notif) { return; }
notify[curve] = notif;
});
$clone.find('br').replaceWith("\n");
$clone.find('> *:not(.cp-mentions)').remove();
var content = clone.innerHTML.trim();
if (!content) { return; }
@ -218,6 +222,7 @@ define([
e.stopPropagation();
if (e.which === 27) {
$(cancel).click();
e.stopImmediatePropagation();
}
if (e.which === 13 && !e.shiftKey) {
// Submit form on Enter is the autocompelte menu is not visible
@ -226,6 +231,7 @@ define([
if (visible) { return; }
} catch (err) {}
$(submit).click();
e.stopImmediatePropagation();
e.preventDefault();
}
}).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 () {
@ -262,6 +284,7 @@ define([
]),
h('div.cp-comment-form-actions', [
cancel,
deleteButton,
submit
])
]);
@ -270,43 +293,60 @@ define([
var redrawComments = function (Env) {
// Don't redraw if there were no change
var str = Sortify(Env.comments || {});
if (str === Env.oldComments) { return; }
Env.oldComments = str;
// Store existing input form in memory
var $oldInput = Env.$container.find('.cp-comment-form').detach();
if ($oldInput.length !== 1) { $oldInput = undefined; }
// Remove everything
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);
Env.$container.append(label);
var show = false;
// If we were adding a new comment, redraw our form
if ($oldInput && !$oldInput.attr('data-uid')) {
show = true;
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');
}).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];
if (!obj || obj.deleted || !Array.isArray(obj.m) || !obj.m.length) {
if (!obj || obj.d || !Array.isArray(obj.m) || !obj.m.length) {
return;
}
// If at least one thread is visible, display the "comments" column
show = true;
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" ?
((Env.comments.authors || {})[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
content.push(h('div.cp-comment'+(i === 0 ? '' : '.cp-comment-reply'), [
content.push(container = h('div.cp-comment'+replyCls, [
h('div.cp-comment-header', [
avatar,
h('span.cp-comment-metadata', [
h('span.cp-comment-author', name),
h('span.cp-comment-time', date.toLocaleString())
])
]),
edit
]),
m
m,
edited
]));
});
@ -386,19 +481,20 @@ define([
reply,
resolve
]));
var $actions = $(actions);
$actions = $(actions);
var div;
Env.$container.append(div = h('div.cp-comment-container', {
'data-uid': key,
tabindex: 1
}, content));
var $div = $(div);
$div = $(div);
$(reply).click(function (e) {
e.stopPropagation();
$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();
@ -434,7 +530,11 @@ define([
// Make sure the submit button is visible: scroll by the height of the form
setTimeout(function () {
Env.$container.scrollTop(Env.$container.scrollTop() + 55);
var yContainer = Env.$container[0].getBoundingClientRect().bottom;
var yActions = form.getBoundingClientRect().bottom;
if (yActions > yContainer) {
Env.$container.scrollTop(Env.$container.scrollTop() + 55);
}
});
});
@ -531,7 +631,7 @@ define([
// If there is no comment stored in the metadata, abort
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;
@ -556,8 +656,8 @@ define([
}
// If this comment was deleted, we're probably using "undo" to restore it:
// remove the "deleted" state and continue
if (obj.deleted) {
delete obj.deleted;
if (obj.d) {
delete obj.d;
changed = true;
}
return id;
@ -575,7 +675,7 @@ define([
// comment has been deleted
var data = Env.comments.data[uid];
if (!data) { return; }
data.deleted = true;
data.d = 1;
//delete Env.comments.data[uid];
changed = true;
});
@ -711,7 +811,7 @@ define([
// Clear data
var data = (Env.comments && Env.comments.data) || {};
Object.keys(data).forEach(function (uid) {
if (data[uid].deleted) { delete data[uid]; }
if (data[uid].d) { delete data[uid]; }
});
// Commit